diff --git a/appliances.md b/appliances.md
index 3593e7d..ee550a0 100644
--- a/appliances.md
+++ b/appliances.md
@@ -500,10 +500,513 @@ card_mod:
```
+
+3 - Smart Dryer
+
+```yaml
+type: custom:mushroom-entity-card
+entity: sensor.dryer_status
+name: Smart Dryer
+icon: mdi:tumble-dryer
+primary_info: name
+secondary_info: state
+tap_action:
+ action: more-info
+icon_color: light-grey
+fill_container: false
+card_mod:
+ style:
+ .: |
+ ha-card {
+ /* ======================== */
+ /* USER CONFIGURATION */
+ /* ======================== */
+
+ /* 1. ENTITIES */
+ {% set ent_progress = 'sensor.dryer_progress' %}
+ {% set ent_timerem = 'sensor.dryer_time_remaining' %}
+ {% set max_time = 160 %}
+ {% set ent_power = 'sensor.smart_plug_power' %}
+
+ /* OPTIONAL Progress Percentage Sensor (if exists) */
+ {% set ent_percent = 'sensor.dryer_progress_percentage' %}
+
+ /* 2. SIZES (Px) */
+ --config-icon-size: 65px;
+ --config-font-primary: 15px;
+ --config-font-secondary: 12px;
+ --config-font-badge: 12px;
+ /* ======================== */
+
+ /* --- SENSORS & TIME --- */
+ {% set status = states(ent_progress) %}
+ {% set status_clean = status | replace('-', ' ') | title %}
+ {% set time_rem = states(ent_timerem) | int(0) %}
+ {% set raw_percent = states(ent_percent) | float(-1) %}
+
+ /* --- POWER CALCULATION --- */
+ {% set power_w = states(ent_power) | float(0) | round %}
+ {% set power_text = ' • ' ~ power_w ~ 'W' if power_w > 0 else '' %}
+
+ /* Format Time (min -> Xh Ym) */
+ {% set hours = (time_rem / 60) | int %}
+ {% set mins = time_rem % 60 %}
+ {% set time_formatted = '%dh %02dm' | format(hours, mins) %}
+
+ /* --- PROGRESS CALCULATION --- */
+ {% if status | lower in ['idle', 'off', 'standby', 'unknown', 'unavailable'] %}
+ {% set progress = 0 %}
+ {% set badge_text = status_clean ~ power_text %}
+ {% else %}
+
+ /* LOGIC: Use Sensor if available, otherwise Calculate */
+ {% if raw_percent >= 0 %}
+ /* Use the sensor provided percentage */
+ {% set progress = raw_percent | int %}
+ {% else %}
+ /* Fallback: Calculate based on max_time */
+ {% set max_cycle_time = max_time %}
+ {% set calc_prog = ((max_cycle_time - time_rem) / max_cycle_time * 100) | int %}
+ {% set progress = [5, [calc_prog, 100] | min] | max %}
+ {% endif %}
+
+ /* Show Status + Time + Power */
+ {% set badge_text = status_clean ~ ' • ' ~ time_formatted ~ power_text %}
+ {% endif %}
+
+ /* --- STATE DEFINITIONS --- */
+ {% set s_lower = status | lower %}
+ {% set is_drying = s_lower in ['drying', 'tumble', 'dry', 'heat', 'drying', 'heating'] %}
+ {% set is_cooling = s_lower in ['cooling', 'cool down', 'anti-crease', 'air fluff'] %}
+ {% set is_done = s_lower in ['finished', 'complete', 'end'] %}
+
+ /* --- ASSIGN ANIMATIONS --- */
+ {% if is_drying %}
+ {% set color = '255, 87, 34' %} /* Deep Orange (Heat) */
+ {% set anim_type = 'steam-rise 2s ease-in-out infinite' %}
+ {% set icon_shake = 'shake 0.8s ease-in-out infinite' %}
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set overlay_img = 'linear-gradient(0deg, transparent, rgba(255,255,255,0.4), transparent)' %}
+ {% elif is_cooling %}
+ {% set color = '33, 150, 243' %} /* Blue (Cooling) */
+ {% set anim_type = 'breeze 3s ease-in-out infinite' %}
+ {% set icon_shake = 'wobble 2s ease-in-out infinite' %}
+ {% set wave_anim = 'wave 6s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.5) 0%, transparent 70%)' %}
+ {% elif is_done %}
+ {% set color = '76, 175, 80' %} /* Green */
+ {% set anim_type = 'sparkle 2s infinite' %}
+ {% set icon_shake = 'none' %}
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.8) 10%, transparent 60%)' %}
+ {% else %}
+ {% set color = '158, 158, 158' %} /* Grey */
+ {% set anim_type = 'none' %}
+ {% set icon_shake = 'none' %}
+ {% set wave_anim = 'none' %}
+ {% set overlay_img = 'none' %}
+ {% endif %}
+
+ /* --- OUTPUT VARIABLES --- */
+ --dryer-color: {{ color }};
+ --dryer-level: {{ progress }}%;
+ --dryer-anim-overlay: {{ anim_type }};
+ --dryer-anim-shake: {{ icon_shake }};
+ --dryer-anim-wave: {{ wave_anim }};
+ --dryer-overlay-bg: {{ overlay_img }};
+ --dryer-badge-content: "{{ badge_text }}";
+
+ transition: all 0.5s ease;
+ overflow: hidden;
+ }
+
+ /* BADGE */
+ ha-card::before {
+ content: var(--dryer-badge-content);
+ position: absolute;
+ top: 10px; right: 10px;
+ background: rgba(var(--dryer-color), 0.15);
+ color: rgb(var(--dryer-color));
+ border: 1px solid rgba(var(--dryer-color), 0.3);
+ padding: 2px 10px;
+ border-radius: 12px;
+ text-transform: uppercase;
+ font-weight: 600;
+ letter-spacing: 0.5px;
+ font-size: var(--config-font-badge);
+ }
+
+ /* BAR */
+ ha-card::after {
+ content: '';
+ position: absolute;
+ bottom: 0; left: 0;
+ height: 4px;
+ width: var(--dryer-level);
+ background: rgb(var(--dryer-color));
+ box-shadow: 0 0 10px rgb(var(--dryer-color));
+ transition: width 0.5s ease;
+ }
+ mushroom-shape-icon$: |
+ .shape {
+ --icon-size: var(--config-icon-size) !important;
+ background: rgba(255, 255, 255, 0.05) !important;
+ overflow: hidden;
+ position: relative;
+ border: 1px solid rgba(255,255,255,0.1);
+
+ /* Apply the animation determined by the Logic below */
+ animation: var(--dryer-anim-shake) !important;
+ transform-origin: 50% 60%;
+ }
+
+ /* Wave Layer */
+ .shape::before {
+ content: '';
+ position: absolute;
+ left: -50%;
+ width: 200%; height: 200%;
+ top: calc(100% - var(--dryer-level));
+ background: rgba(var(--dryer-color), 0.6);
+ border-radius: 40%;
+ animation: var(--dryer-anim-wave);
+ }
+
+ /* Overlay Layer (Bubbles/Steam) */
+ .shape::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: var(--dryer-overlay-bg);
+ background-size: 100% 100%;
+ animation: var(--dryer-anim-overlay);
+ z-index: 2;
+ }
+
+ /* The Icon Itself */
+ ha-icon {
+ z-index: 3;
+ mix-blend-mode: overlay;
+ color: white !important;
+ }
+
+ /* --- KEYFRAMES --- */
+ @keyframes wave {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+ }
+ @keyframes shake {
+ 0%, 100% { transform: rotate(0deg); }
+ 25% { transform: rotate(10deg) translateY(-2px); }
+ 50% { transform: rotate(0deg); }
+ 75% { transform: rotate(-10deg) translateY(2px); }
+ }
+ @keyframes wobble {
+ 0%, 100% { transform: rotate(0deg); }
+ 50% { transform: rotate(5deg); }
+ }
+ @keyframes steam-rise {
+ 0% { opacity: 0; transform: translateY(10px) scale(0.9); }
+ 50% { opacity: 0.6; }
+ 100% { opacity: 0; transform: translateY(-20px) scale(1.1); }
+ }
+ @keyframes breeze {
+ 0% { opacity: 0.2; transform: scale(0.95); }
+ 50% { opacity: 0.5; transform: scale(1.05); }
+ 100% { opacity: 0.2; transform: scale(0.95); }
+ }
+ @keyframes sparkle {
+ 0%, 100% { opacity: 0.3; transform: scale(0.9); }
+ 50% { opacity: 1; transform: scale(1.1); }
+ }
+ mushroom-state-info$: |
+ .container .primary {
+ font-size: var(--config-font-primary) !important;
+ }
+ .container .secondary {
+ font-size: var(--config-font-secondary) !important;
+ }
+
+```
+
+
+
+4 - Smart Combo Washing machine & Dryer
+
+```yaml
+type: custom:mushroom-entity-card
+entity: sensor.combo_machine_status
+name: Smart Combo
+icon: mdi:washing-machine
+primary_info: name
+secondary_info: state
+tap_action:
+ action: more-info
+icon_color: light-grey
+fill_container: false
+card_mod:
+ style:
+ .: |
+ ha-card {
+ /* ======================== */
+ /* USER CONFIGURATION */
+ /* ======================== */
+
+ /* 1. ENTITIES */
+ {% set ent_status = 'sensor.combo_machine_progress' %}
+ {% set ent_timerem = 'sensor.combo_machine_time_remaining' %}
+ {% set max_time = 180 %}
+
+ {% set ent_power = 'sensor.smart_plug_power' %}
+
+ /* OPTIONAL Progress Percentage Sensor (if exists) */
+ {% set ent_percent = 'sensor.combo_machine_progress_percentage' %}
+
+ /* 2. SIZES (Px) */
+ --config-icon-size: 65px;
+ --config-font-primary: 15px;
+ --config-font-secondary: 12px;
+ --config-font-badge: 12px;
+ /* ======================== */
+
+ /* --- SENSORS & DATA --- */
+ {% set status = states(ent_status) %}
+ {% set status_clean = status | replace('-', ' ') | title %}
+ {% set time_rem = states(ent_timerem) | int(0) %}
+ {% set raw_percent = states(ent_percent) | float(-1) %}
+
+ /* --- POWER DISPLAY --- */
+ {% set power_w = states(ent_power) | float(0) | round %}
+ {% set power_text = ' • ' ~ power_w ~ 'W' if power_w > 0 else '' %}
+
+ /* Format Time (min -> Xh Ym) */
+ {% set hours = (time_rem / 60) | int %}
+ {% set mins = time_rem % 60 %}
+ {% set time_formatted = '%dh %02dm' | format(hours, mins) %}
+
+ /* --- PROGRESS CALCULATION --- */
+ {% if status | lower in ['idle', 'off', 'standby', 'unknown', 'unavailable'] %}
+ {% set progress = 0 %}
+ {% set badge_text = status_clean ~ power_text %}
+ {% else %}
+
+ /* LOGIC: Use Sensor if available, otherwise Calculate */
+ {% if raw_percent >= 0 %}
+ {% set progress = raw_percent | int %}
+ {% else %}
+ {% set max_cycle_time = max_time %}
+ {% set calc_prog = ((max_cycle_time - time_rem) / max_cycle_time * 100) | int %}
+ {% set progress = [5, [calc_prog, 100] | min] | max %}
+ {% endif %}
+
+ {% set badge_text = status_clean ~ ' • ' ~ time_formatted ~ power_text %}
+ {% endif %}
+
+ /* --- STATE LOGIC (The Core Logic) --- */
+ {% set s_lower = status | lower %}
+
+ /* 1. Water Phases */
+ {% set is_washing = s_lower in ['wash', 'washing', 'rinse', 'rinsing', 'pre-wash', 'soak'] %}
+ {% set is_spinning = s_lower in ['spin', 'spinning', 'drain'] %}
+
+ /* 2. Heat Phases (Dryer Logic) */
+ {% set is_drying = s_lower in ['dry', 'drying', 'tumble'] %}
+ {% set is_cooling = s_lower in ['cooling', 'cool down', 'anti-crease'] %}
+
+ /* 3. Finished */
+ {% set is_done = s_lower in ['finished', 'complete', 'end'] %}
+
+ /* --- ANIMATION & COLOR ASSIGNMENT --- */
+ {% if is_drying %}
+ /* DRYING MODE: Orange + Steam + Shake */
+ {% set color = '255, 87, 34' %}
+ {% set anim_type = 'steam-rise 2s ease-in-out infinite' %}
+ {% set icon_shake = 'shake 0.8s ease-in-out infinite' %}
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set overlay_img = 'linear-gradient(0deg, transparent, rgba(255,255,255,0.4), transparent)' %}
+
+ {% elif is_cooling %}
+ /* COOLING MODE: Light Blue + Breeze + Wobble */
+ {% set color = '33, 150, 243' %}
+ {% set anim_type = 'breeze 3s ease-in-out infinite' %}
+ {% set icon_shake = 'wobble 2s ease-in-out infinite' %}
+ {% set wave_anim = 'wave 6s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.5) 0%, transparent 70%)' %}
+
+ {% elif is_spinning %}
+ /* SPINNING MODE: Cyan + Fast Spin + Fast Wave */
+ {% set color = '0, 255, 255' %}
+ {% set anim_type = 'none' %}
+ {% set icon_shake = 'washer-spin-smooth 0.8s linear infinite' %}
+ {% set wave_anim = 'wave 2s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.3) 10%, transparent 60%)' %}
+
+ {% elif is_washing %}
+ /* WASHING MODE: Blue + Bubbles + Slow Shake */
+ {% set color = '33, 150, 243' %}
+ {% set anim_type = 'bubbles 1s linear infinite' %}
+ {% set icon_shake = 'shake 1.5s ease-in-out infinite' %}
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(2px 2px at 20% 80%, white, transparent), radial-gradient(2px 2px at 50% 70%, white, transparent)' %}
+
+ {% elif is_done %}
+ /* DONE: Green + Sparkle */
+ {% set color = '76, 175, 80' %}
+ {% set anim_type = 'sparkle 2s infinite' %}
+ {% set icon_shake = 'none' %}
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.8) 10%, transparent 60%)' %}
+
+ {% else %}
+ /* IDLE/OFF: Grey */
+ {% set color = '158, 158, 158' %}
+ {% set anim_type = 'none' %}
+ {% set icon_shake = 'none' %}
+ {% set wave_anim = 'none' %}
+ {% set overlay_img = 'none' %}
+ {% endif %}
+
+ /* --- OUTPUT VARIABLES --- */
+ --combo-color: {{ color }};
+ --combo-level: {{ progress }}%;
+ --combo-anim-overlay: {{ anim_type }};
+ --combo-anim-shake: {{ icon_shake }};
+ --combo-anim-wave: {{ wave_anim }};
+ --combo-overlay-bg: {{ overlay_img }};
+ --combo-badge-content: "{{ badge_text }}";
+
+ transition: all 0.5s ease;
+ overflow: hidden;
+ }
+
+ /* BADGE */
+ ha-card::before {
+ content: var(--combo-badge-content);
+ position: absolute;
+ top: 10px; right: 10px;
+ background: rgba(var(--combo-color), 0.15);
+ color: rgb(var(--combo-color));
+ border: 1px solid rgba(var(--combo-color), 0.3);
+ padding: 2px 10px;
+ border-radius: 12px;
+ text-transform: uppercase;
+ font-weight: 600;
+ letter-spacing: 0.5px;
+ font-size: var(--config-font-badge);
+ }
+
+ /* PROGRESS BAR */
+ ha-card::after {
+ content: '';
+ position: absolute;
+ bottom: 0; left: 0;
+ height: 4px;
+ width: var(--combo-level);
+ background: rgb(var(--combo-color));
+ box-shadow: 0 0 10px rgb(var(--combo-color));
+ transition: width 0.5s ease;
+ }
+ mushroom-shape-icon$: |
+ .shape {
+ --icon-size: var(--config-icon-size) !important;
+ background: rgba(255, 255, 255, 0.05) !important;
+ overflow: hidden;
+ position: relative;
+ border: 1px solid rgba(255,255,255,0.1);
+
+ /* Apply Animation */
+ animation: var(--combo-anim-shake) !important;
+ transform-origin: center center;
+ }
+
+ /* Wave Layer (Liquid) */
+ .shape::before {
+ content: '';
+ position: absolute;
+ left: -50%;
+ width: 200%; height: 200%;
+ top: calc(100% - var(--combo-level));
+ background: rgba(var(--combo-color), 0.6);
+ border-radius: 40%;
+ animation: var(--combo-anim-wave);
+ }
+
+ /* Overlay Layer (Bubbles/Steam/Sparkle) */
+ .shape::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: var(--combo-overlay-bg);
+ background-size: 100% 100%;
+ animation: var(--combo-anim-overlay);
+ z-index: 2;
+ }
+
+ /* Icon */
+ ha-icon {
+ z-index: 3;
+ mix-blend-mode: overlay;
+ color: white !important;
+ }
+
+ /* --- KEYFRAMES --- */
+ @keyframes wave {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+ }
+ @keyframes shake {
+ 0%, 100% { transform: rotate(0deg); }
+ 25% { transform: rotate(5deg) translateY(-1px); }
+ 75% { transform: rotate(-5deg) translateY(1px); }
+ }
+ @keyframes wobble {
+ 0%, 100% { transform: rotate(0deg); }
+ 50% { transform: rotate(5deg); }
+ }
+ @keyframes washer-spin-smooth {
+ 0% {
+ transform: rotate(0deg);
+ box-shadow: inset 0 0 0 2px rgba(var(--combo-color), 0.7);
+ }
+ 100% {
+ transform: rotate(360deg);
+ box-shadow: inset 0 0 0 2px rgba(var(--combo-color), 0.7);
+ }
+ }
+ @keyframes bubbles {
+ 0% { transform: translateY(10px); opacity: 0; }
+ 50% { opacity: 1; }
+ 100% { transform: translateY(-20px); opacity: 0; }
+ }
+ @keyframes steam-rise {
+ 0% { opacity: 0; transform: translateY(10px) scale(0.9); }
+ 50% { opacity: 0.6; }
+ 100% { opacity: 0; transform: translateY(-20px) scale(1.1); }
+ }
+ @keyframes breeze {
+ 0% { opacity: 0.2; transform: scale(0.95); }
+ 50% { opacity: 0.5; transform: scale(1.05); }
+ 100% { opacity: 0.2; transform: scale(0.95); }
+ }
+ @keyframes sparkle {
+ 0%, 100% { opacity: 0.3; transform: scale(0.9); }
+ 50% { opacity: 1; transform: scale(1.1); }
+ }
+ mushroom-state-info$: |
+ .container .primary {
+ font-size: var(--config-font-primary) !important;
+ }
+ .container .secondary {
+ font-size: var(--config-font-secondary) !important;
+ }
+
+```
+
+
---
-3 - Dumb Dishwasher (smart plug)
+5 - Dumb Dishwasher (smart plug)
```yaml
type: custom:mushroom-entity-card
@@ -531,7 +1034,7 @@ card_mod:
/* Optional Helper (Leave as is if you don't have one) */
/* If in-use, then you can use this entity as the main card entity above */
/* and it will show useful secondary info like */
- /* (Off, Running) instead of repeating wattage */
+ /* (Not Running, Running) instead of repeating wattage */
{% set ent_helper = 'binary_sensor.dishwasher_active_delay' %}
@@ -769,7 +1272,7 @@ card_mod:
---
-4 - Dumb Washing Machine (smart plug)
+6 - Dumb Washing Machine (smart plug)
```yaml
type: custom:mushroom-entity-card
@@ -797,7 +1300,7 @@ card_mod:
/* Optional Helper (Leave as is if you don't have one) */
/* If in-use, then you can use this entity as the main card entity above */
/* and it will show useful secondary info like */
- /* (Off, Running) instead of repeating wattage */
+ /* (Not Running, Running) instead of repeating wattage */
{% set ent_helper = 'binary_sensor.washing_machine_active_delay' %}
@@ -1048,12 +1551,623 @@ card_mod:
---
-Smart and dumb Dryer cards (coming soon)
+7 - Dumb Dryer (smart plug)
+```yaml
+type: custom:mushroom-entity-card
+entity: binary_sensor.dryer_active_delay
+name: Dumb Dryer
+icon: mdi:tumble-dryer
+primary_info: name
+secondary_info: state
+tap_action:
+ action: more-info
+fill_container: false
+icon_color: white
+card_mod:
+ style:
+ .: |
+ ha-card {
+ /* ======================== */
+ /* USER CONFIGURATION */
+ /* ======================== */
+
+ {% set ent_switch = 'switch.smart_plug' %}
+ {% set ent_power = 'sensor.smart_plug_power' %}
+
+ /* Optional Helper (Leave as is if you don't have one) */
+ /* If in-use, then you can use this entity as the main card entity above */
+ /* and it will show useful secondary info like */
+ /* (Not Running, Running) instead of repeating wattage */
+
+ {% set ent_helper = 'binary_sensor.dryer_active_delay' %}
+
+ /* Thresholds */
+
+ {% set thresh_heat = 500 %}
+ {% set thresh_active = 5 %}
+
+ /* SIZES */
+ --config-icon-size: 65px;
+ --config-font-primary: 15px;
+ --config-font-secondary: 12px;
+ --config-font-badge: 11px;
+ /* ======================== */
+
+ /* --- DEFAULTS --- */
+ {% set icon_shake = 'none' %}
+ {% set anim_type = 'none' %}
+ {% set wave_anim = 'none' %}
+ {% set overlay_img = 'none' %}
+ {% set level = 0 %}
+ {% set badge_content = '' %}
+ {% set time_str = '' %}
+ {% set color = '158, 158, 158' %}
+
+ /* --- DATA FETCHING --- */
+ {% set power = states(ent_power) | float(0) | int %}
+ {% set switch_state = states(ent_switch) %}
+
+ /* Check if helpers exist in HA */
+ {% set has_helper = states(ent_helper) not in ['unknown', 'unavailable', 'none'] %}
+
+ /* --- SMART LOGIC --- */
+ {% if has_helper %}
+ {% set status_bin = states(ent_helper) %}
+ {% else %}
+ /* Fallback: Active if power > 5W */
+ {% set status_bin = 'on' if power > thresh_active else 'off' %}
+ {% endif %}
+
+ /* --- DURATION TIMER --- */
+ {% if status_bin == 'on' and switch_state == 'on' %}
+ {% if has_helper %}
+ {% set start_time = states[ent_helper].last_changed %}
+ {% set seconds = as_timestamp(now()) - as_timestamp(start_time) %}
+ {% set hours = (seconds / 3600) | int %}
+ {% set mins = ((seconds % 3600) / 60) | int %}
+ {% if seconds > 60 %}
+ {% set time_str = '%dh %02dm' | format(hours, mins) %}
+ {% else %}
+ {% set time_str = 'Started' %}
+ {% endif %}
+ {% else %}
+ {% set time_str = 'Started' %}
+ {% endif %}
+ {% else %}
+ {% set time_str = '' %}
+ {% endif %}
+
+ /* --- STATE LOGIC --- */
+ {% if switch_state == 'off' %}
+ {% set status_text = 'Plug Off' %}
+ {% set color = '244, 67, 54' %}
+ {% set badge_content = status_text %}
+
+ {% elif switch_state in ['unavailable', 'unknown'] %}
+ {% set status_text = 'Offline' %}
+ {% set color = '158, 158, 158' %}
+ {% set badge_content = status_text %}
+
+ {% elif status_bin == 'on' %}
+
+ /* --- HIGH POWER (HEATING/DRYING) --- */
+ {% if power > thresh_heat %}
+ {% set status_text = 'Drying' %}
+ {% set color = '255, 87, 34' %} /* Deep Orange */
+ {% set anim_type = 'steam-rise 2s ease-in-out infinite' %}
+ {% set overlay_img = 'linear-gradient(0deg, transparent, rgba(255,255,255,0.4), transparent)' %}
+ {% set icon_shake = 'shake 0.8s ease-in-out infinite' %}
+
+ /* --- MEDIUM POWER (TUMBLING/COOLING) --- */
+ {% else %}
+ {% set status_text = 'Tumbling' %}
+ {% set color = '33, 150, 243' %} /* Blue (Air) */
+ {% set anim_type = 'breeze 3s ease-in-out infinite' %}
+ {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.5) 0%, transparent 70%)' %}
+ {% set icon_shake = 'wobble 2s ease-in-out infinite' %}
+ {% endif %}
+
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set level = 60 %}
+ {% set badge_content = status_text ~ " • " ~ power ~ " W" %}
+
+ {% else %}
+ /* --- IDLE STATE --- */
+ {% set status_text = 'Idle' %}
+ {% set color = '158, 158, 158' %}
+ {% set badge_content = status_text ~ " • " ~ power ~ " W" %}
+ {% endif %}
+
+ /* --- OUTPUT VARIABLES --- */
+ --dryer-color: {{ color }};
+ --dryer-level: {{ level }}%;
+ --dryer-anim-overlay: {{ anim_type }};
+ --dryer-anim-shake: {{ icon_shake }};
+ --dryer-anim-wave: {{ wave_anim }};
+ --dryer-overlay-bg: {{ overlay_img }};
+ --dryer-badge-status: "{{ badge_content }}";
+
+ --dryer-time-text: "{{ time_str }}";
+ --dryer-time-display: {{ 'block' if time_str | length > 0 else 'none' }};
+
+ transition: all 0.5s ease;
+ overflow: hidden;
+ }
+
+ /* 1. STATUS BADGE */
+ ha-card::before {
+ content: var(--dryer-badge-status);
+ position: absolute;
+ top: 8px; right: 10px;
+ background: rgba(var(--dryer-color), 0.15);
+ color: rgb(var(--dryer-color));
+ border: 1px solid rgba(var(--dryer-color), 0.3);
+ padding: 2px 8px;
+ border-radius: 10px;
+ font-weight: 700;
+ text-transform: uppercase;
+ font-size: var(--config-font-badge);
+ letter-spacing: 0.5px;
+ z-index: 5;
+ }
+
+ /* 2. PROGRESS BAR (Visual Only) */
+ ha-card::after {
+ content: '';
+ position: absolute;
+ bottom: 0; left: 0;
+ height: 4px;
+ width: var(--dryer-level);
+ background: rgb(var(--dryer-color));
+ box-shadow: 0 0 10px rgb(var(--dryer-color));
+ transition: width 0.5s ease;
+ z-index: 1;
+ }
+ mushroom-state-info$: >
+ .container .primary { font-size: var(--config-font-primary) !important; }
+ .container .secondary { font-size: var(--config-font-secondary)
+ !important; }
+
+ .container::after {
+ content: var(--dryer-time-text);
+ position: absolute;
+ top: 40px;
+ right: 10px;
+ color: var(--primary-text-color);
+ background: rgba(var(--rgb-primary-text-color), 0.05);
+ border: 1px solid rgba(var(--rgb-primary-text-color), 0.1);
+ padding: 2px 8px;
+ border-radius: 10px;
+ font-weight: 700;
+ font-size: var(--config-font-badge);
+ letter-spacing: 0.5px;
+ display: var(--dryer-time-display);
+ }
+ mushroom-shape-icon$: >
+ .shape {
+ --icon-size: var(--config-icon-size) !important;
+ background: rgba(255, 255, 255, 0.05) !important;
+ overflow: hidden !important;
+ position: relative;
+ border: 1px solid rgba(255,255,255,0.1);
+ animation: var(--dryer-anim-shake) !important;
+ transform-origin: 50% 50%;
+ }
+
+ .shape::before {
+ content: '';
+ position: absolute;
+ left: -50%;
+ width: 200%; height: 200%;
+ top: calc(100% - var(--dryer-level));
+ background: rgba(var(--dryer-color), 0.6);
+ border-radius: 40%;
+ animation: var(--dryer-anim-wave);
+ }
+
+ .shape::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: var(--dryer-overlay-bg);
+ background-size: 100% 100%;
+ animation: var(--dryer-anim-overlay);
+ z-index: 2;
+ }
+
+ ha-icon {
+ z-index: 3;
+ mix-blend-mode: overlay;
+ color: white !important;
+ }
+
+ /* --- ANIMATIONS --- */ @keyframes wave { from { transform: rotate(0deg);
+ } to { transform: rotate(360deg); } }
+
+ @keyframes shake {
+ 0%, 100% { transform: rotate(0deg); }
+ 25% { transform: rotate(10deg) translateY(-2px); }
+ 50% { transform: rotate(0deg); }
+ 75% { transform: rotate(-10deg) translateY(2px); }
+ }
+
+ @keyframes wobble {
+ 0%, 100% { transform: rotate(0deg); }
+ 50% { transform: rotate(5deg); }
+ }
+
+ @keyframes steam-rise {
+ 0% { opacity: 0; transform: translateY(10px) scale(0.9); }
+ 50% { opacity: 0.6; }
+ 100% { opacity: 0; transform: translateY(-20px) scale(1.1); }
+ }
+
+ @keyframes breeze {
+ 0% { opacity: 0.2; transform: scale(0.95); }
+ 50% { opacity: 0.5; transform: scale(1.05); }
+ 100% { opacity: 0.2; transform: scale(0.95); }
+ }
+
+```
+
+
+
+Dumb Dryer (Helper/Template)
+
+```yaml
+ - binary_sensor:
+ - name: "Dryer Active delay"
+ unique_id: dryer_active_status
+ # Change the entity_id below to match your actual smart plug
+ state: >
+ {{ states('sensor.smart_plug')|float(0) > 5 }}
+ delay_off: "00:05:00"
+ device_class: running
+ icon: mdi:tumble-dryer
+```
---
+
+8 - Combo Washing machine & Dryer (smart plug)
+
+```yaml
+type: custom:mushroom-entity-card
+entity: binary_sensor.combo_machine_active_delay
+name: Dumb Combo
+icon: mdi:washing-machine
+primary_info: name
+secondary_info: state
+tap_action:
+ action: more-info
+fill_container: false
+icon_color: white
+card_mod:
+ style:
+ .: |
+ ha-card {
+ /* ======================== */
+ /* USER CONFIGURATION */
+ /* ======================== */
+
+ /* 1. ENTITIES */
+ {% set ent_switch = 'switch.smart_plug' %}
+ {% set ent_power = 'sensor.smart_plug_power' %}
+
+ /* Optional Helpers (Leave as is if you don't have one) */
+ /* If in-use, then you can use "ent_run" entity as the main card entity above */
+ /* and it will show useful secondary info like */
+ /* (Not Running, Running) instead of repeating wattage */
+
+ {% set ent_run = 'binary_sensor.combo_machine_active_delay' %}
+ {% set ent_dry_mode = 'binary_sensor.combo_machine_drying_detector' %}
+
+ /* THRESHOLDS */
+ {% set thresh_high = 800 %}
+ {% set thresh_active = 5 %}
+
+ /* 2. SIZES */
+ --config-icon-size: 65px;
+ --config-font-primary: 15px;
+ --config-font-secondary: 12px;
+ --config-font-badge: 11px;
+ /* ======================== */
+
+ /* --- DEFAULTS --- */
+ {% set icon_shake = 'none' %}
+ {% set anim_type = 'none' %}
+ {% set wave_anim = 'none' %}
+ {% set overlay_img = 'none' %}
+ {% set level = 0 %}
+ {% set badge_content = '' %}
+ {% set time_str = '' %}
+ {% set color = '158, 158, 158' %}
+
+ /* --- DATA FETCHING --- */
+ {% set power = states(ent_power) | float(0) | int %}
+ {% set switch_state = states(ent_switch) %}
+
+ /* Check if helpers exist in HA */
+ {% set run_state = states(ent_run) %}
+ {% set dry_state = states(ent_dry_mode) %}
+ {% set has_run_helper = run_state not in ['unknown', 'unavailable', 'none'] %}
+ {% set has_dry_helper = dry_state not in ['unknown', 'unavailable', 'none'] %}
+
+ /* --- SMART LOGIC (With Fallbacks) --- */
+ {% if has_run_helper %}
+ /* Use Helper */
+ {% set is_running = run_state == 'on' %}
+ {% else %}
+ /* Fallback: Power > 5W */
+ {% set is_running = power > thresh_active %}
+ {% endif %}
+
+ {% if has_dry_helper %}
+ /* Use Helper */
+ {% set is_drying_mode = dry_state == 'on' %}
+ {% else %}
+ /* Fallback: We can't safely guess drying mode without a timer/helper */
+ /* So we default to False (Washing) to be safe */
+ {% set is_drying_mode = false %}
+ {% endif %}
+
+ /* --- TIMER CALCULATION --- */
+ {% if is_running and switch_state == 'on' %}
+ {% if has_run_helper %}
+ /* Calculate precise time if helper exists */
+ {% set start_time = states[ent_run].last_changed %}
+ {% set seconds = as_timestamp(now()) - as_timestamp(start_time) %}
+ {% set hours = (seconds / 3600) | int %}
+ {% set mins = ((seconds % 3600) / 60) | int %}
+ {% if seconds > 60 %}
+ {% set time_str = '%dh %02dm' | format(hours, mins) %}
+ {% else %}
+ {% set time_str = 'Started' %}
+ {% endif %}
+ {% else %}
+ /* Generic text if no helper */
+ {% set time_str = 'Running' %}
+ {% endif %}
+ {% else %}
+ {% set time_str = '' %}
+ {% endif %}
+
+ /* --- MAIN LOGIC --- */
+
+ /* PRIORITY 1: CHECK SWITCH STATE */
+ {% if switch_state in ['unavailable', 'unknown'] %}
+ {% set status_text = 'Offline' %}
+ {% set color = '158, 158, 158' %} /* Dark Grey */
+ {% set badge_content = status_text %}
+ {% set level = 0 %}
+
+ /* PRIORITY 1: CHECK SWITCH STATE */
+ {% elif switch_state == 'off' %}
+ {% set status_text = 'Plug Off' %}
+ {% set color = '244, 67, 54' %} /* Red */
+ {% set badge_content = status_text %}
+ {% set level = 0 %}
+
+ /* PRIORITY 2: MACHINE IDLE */
+ {% elif not is_running %}
+ {% set status_text = 'Idle' %}
+ {% set color = '158, 158, 158' %} /* Grey */
+ /* ADDED POWER DISPLAY HERE */
+ {% set badge_content = status_text ~ " • " ~ power ~ " W" %}
+
+ /* PRIORITY 3: MACHINE RUNNING */
+ {% else %}
+
+ {% if is_drying_mode %}
+ /* === DRYING === */
+ {% set status_text = 'Drying' %}
+ {% set color = '255, 87, 34' %} /* Orange */
+ {% set anim_type = 'steam-rise 2s ease-in-out infinite' %}
+ {% set overlay_img = 'linear-gradient(0deg, transparent, rgba(255,255,255,0.4), transparent)' %}
+ {% set icon_shake = 'shake 0.8s ease-in-out infinite' if power > 100 else 'wobble 2s ease-in-out infinite' %}
+
+ {% else %}
+ /* === WASHING === */
+ {% set status_text = 'Washing' %}
+ {% set color = '33, 150, 243' %} /* Blue */
+ {% set anim_type = 'bubbles 2s linear infinite' %}
+ {% set overlay_img = 'radial-gradient(2px 2px at 20% 80%, white, transparent), radial-gradient(2px 2px at 50% 70%, white, transparent)' %}
+
+ {% if power > thresh_high %}
+ {% set status_text = 'Spinning' %}
+ {% set color = '0, 255, 255' %} /* Cyan */
+ {% set icon_shake = 'washer-spin-smooth 0.8s linear infinite' %}
+ {% else %}
+ {% set icon_shake = 'shake 2s ease-in-out infinite' %}
+ {% endif %}
+ {% endif %}
+
+ {% set wave_anim = 'wave 4s linear infinite' %}
+ {% set level = 60 %}
+ {% set badge_content = status_text ~ " • " ~ power ~ " W" %}
+
+ {% endif %}
+
+ /* --- CSS VARIABLES --- */
+ --combo-color: {{ color }};
+ --combo-level: {{ level }}%;
+ --combo-anim-overlay: {{ anim_type }};
+ --combo-anim-shake: {{ icon_shake }};
+ --combo-anim-wave: {{ wave_anim }};
+ --combo-overlay-bg: {{ overlay_img }};
+ --combo-badge-status: "{{ badge_content }}";
+
+ --combo-time-text: "{{ time_str }}";
+ --combo-time-display: {{ 'block' if time_str | length > 0 else 'none' }};
+
+ transition: all 0.5s ease;
+ overflow: hidden;
+ }
+
+ /* BADGE */
+ ha-card::before {
+ content: var(--combo-badge-status);
+ position: absolute;
+ top: 8px; right: 10px;
+ background: rgba(var(--combo-color), 0.15);
+ color: rgb(var(--combo-color));
+ border: 1px solid rgba(var(--combo-color), 0.3);
+ padding: 2px 8px;
+ border-radius: 10px;
+ font-weight: 700;
+ text-transform: uppercase;
+ font-size: var(--config-font-badge);
+ letter-spacing: 0.5px;
+ z-index: 5;
+ }
+
+ /* BAR */
+ ha-card::after {
+ content: '';
+ position: absolute;
+ bottom: 0; left: 0;
+ height: 4px;
+ width: var(--combo-level);
+ background: rgb(var(--combo-color));
+ box-shadow: 0 0 10px rgb(var(--combo-color));
+ transition: width 0.5s ease;
+ z-index: 1;
+ }
+ mushroom-state-info$: >
+ .container .primary { font-size: var(--config-font-primary) !important; }
+ .container .secondary { font-size: var(--config-font-secondary)
+ !important; }
+
+ .container::after {
+ content: var(--combo-time-text);
+ position: absolute;
+ top: 40px;
+ right: 10px;
+ color: var(--primary-text-color);
+ background: rgba(var(--rgb-primary-text-color), 0.05);
+ border: 1px solid rgba(var(--rgb-primary-text-color), 0.1);
+ padding: 2px 8px;
+ border-radius: 10px;
+ font-weight: 700;
+ font-size: var(--config-font-badge);
+ letter-spacing: 0.5px;
+ display: var(--combo-time-display);
+ }
+ mushroom-shape-icon$: >
+ .shape {
+ --icon-size: var(--config-icon-size) !important;
+ background: rgba(255, 255, 255, 0.05) !important;
+ overflow: hidden !important;
+ position: relative;
+ border: 1px solid rgba(255,255,255,0.1);
+ animation: var(--combo-anim-shake) !important;
+ transform-origin: 50% 50%;
+ }
+
+ .shape::before {
+ content: '';
+ position: absolute;
+ left: -50%;
+ width: 200%; height: 200%;
+ top: calc(100% - var(--combo-level));
+ background: rgba(var(--combo-color), 0.6);
+ border-radius: 40%;
+ animation: var(--combo-anim-wave);
+ }
+
+ .shape::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: var(--combo-overlay-bg);
+ background-size: 100% 100%;
+ animation: var(--combo-anim-overlay);
+ z-index: 2;
+ }
+
+ ha-icon {
+ z-index: 3;
+ mix-blend-mode: overlay;
+ color: white !important;
+ }
+
+ @keyframes wave { from { transform: rotate(0deg); } to { transform:
+ rotate(360deg); } }
+
+ @keyframes shake {
+ 0%, 100% { transform: rotate(0deg); }
+ 25% { transform: rotate(10deg) translateY(-2px); }
+ 50% { transform: rotate(0deg); }
+ 75% { transform: rotate(-10deg) translateY(2px); }
+ }
+
+ @keyframes wobble {
+ 0%, 100% { transform: rotate(0deg); }
+ 50% { transform: rotate(5deg); }
+ }
+
+ @keyframes steam-rise {
+ 0% { opacity: 0; transform: translateY(10px) scale(0.9); }
+ 50% { opacity: 0.6; }
+ 100% { opacity: 0; transform: translateY(-20px) scale(1.1); }
+ }
+
+ @keyframes bubbles {
+ 0% { transform: translateY(10px); opacity: 0; }
+ 50% { opacity: 1; }
+ 100% { transform: translateY(-20px); opacity: 0; }
+ }
+
+ @keyframes washer-spin-smooth {
+ 0% {
+ transform: rotate(0deg) translate(0,0);
+ box-shadow: inset 0 0 0 2px rgba(var(--combo-color), 0.7);
+ }
+ 25% { transform: rotate(90deg) translate(0.5px, 0.5px); }
+ 50% { transform: rotate(180deg) translate(0,0); }
+ 75% { transform: rotate(270deg) translate(-0.5px, -0.5px); }
+ 100% {
+ transform: rotate(360deg) translate(0,0);
+ box-shadow: inset 0 0 0 2px rgba(var(--combo-color), 0.7);
+ }
+ }
+
+```
+
+
+
+Dumb Combo Washing machine & Dryer (Helper/Template)
+
+```yaml
+ - binary_sensor:
+ # 1. Main "Combo Machine Running" Detector
+ - name: "Combo Machine Active Delay"
+ unique_id: combo_machine_active_delay
+ device_class: running
+ icon: mdi:washing-machine
+ state: >
+ {{ states('sensor.plug_6_local_power')|float(0) > 5 }}
+ delay_off: "00:05:00" # Wait 5 min before saying it's off
+
+ # 2. "Drying Mode" Detector
+ # Logic If we see HIGH power for a sustained period, we assume Drying.
+ # Note: Washing heaters cycle on/off quickly. Dryers stay on longer.
+ - name: "Combo Machine Drying Detector"
+ unique_id: combo_machine_drying_detector
+ state: >
+ {{ states('sensor.plug_6_local_power')|float(0) > 800 }}
+ # MUST be high for 15 mins to count as drying
+ delay_on: "00:15:00"
+ # Keeps drying active during cool down
+ delay_off: "00:05:00"
+```
+
+
+---
+
+
[paypal_me_shield]: https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white
[paypal_me]: https://paypal.me/anasboxsupport