[![Revolut.Me][revolut_me_shield]][revolut_me] [![PayPal.Me][paypal_me_shield]][paypal_me] [![ko_fi][ko_fi_shield]][ko_fi_me] [![buymecoffee][buy_me_coffee_shield]][buy_me_coffee_me] [![patreon][patreon_shield]][patreon_me]
# Home Assistant [Batch 6](https://youtu.be/RZncjsCWjTw) Collection. Other collections? watch these YouTube videos for more cards and instructions: [Batch 1](https://youtu.be/5vYz37AqSO4) | [Batch 2](https://youtu.be/izx0JMrnhWE) | [Batch 3](https://youtu.be/SrFbC1ae35E) | [Batch 4](https://youtu.be/avAg9CR9TRc) | [Batch 5](https://youtu.be/5k6DfaymBZE)
> [!NOTE] > If you are using the **Sections** view type, you may need to set `rows` to around `1.5` for the card, > otherwise the card may appear compressed. > > ```yaml > grid_options: > rows: 1.5 > ```
# Cards: 665270527-ae6cccdf-0a74-4f4f-b61f-e893fa04d808
Presence sensor card ```yaml type: custom:button-card entity: binary_sensor.aqara_presence_fp300_presence name: Living Room show_state: false show_label: true show_icon: false variables: distance: sensor.aqara_presence_fp300_target_distance show_distance: true range: number.aqara_presence_fp300_detection_range show_range: true max_supported_limit: 6 zone_steps: 24 track_button: button.aqara_presence_fp300_track_target_distance show_track_button: true temp: sensor.aqara_presence_fp300_temperature humidity: sensor.aqara_presence_fp300_humidity lux: sensor.aqara_presence_fp300_illuminance show_environment: true temp_low: 18 temp_mid: 23 temp_high: 27 hum_low: 30 hum_high: 60 lux_min: 50 lux_max: 400 size_shape: 75px size_card_height: 125px font_primary: 15px font_secondary: 12px font_badge: 10px styles: card: - --config-shape-size: '[[[ return variables.size_shape ]]]' - --config-card-height: > [[[ return variables.show_range !== false ? variables.size_card_height : '99px'; ]]] - --config-font-primary: '[[[ return variables.font_primary ]]]' - --config-font-secondary: '[[[ return variables.font_secondary ]]]' - --config-font-badge: '[[[ return variables.font_badge ]]]' - height: var(--config-card-height) !important - padding: 0px !important - overflow: hidden - position: relative grid: - padding: 12px 16px - height: 100% - box-sizing: border-box - grid-template-areas: '"radar n" "radar l"' - grid-template-columns: var(--config-shape-size) 1fr - grid-template-rows: auto auto - align-content: start - gap: 0px 14px - position: relative - z-index: 2 name: - justify-self: start - font-size: var(--config-font-primary) - font-weight: 500 - align-self: end - margin-bottom: 2px - position: relative - color: var(--primary-text-color) label: - justify-self: start - font-size: var(--config-font-secondary) - opacity: 0.7 - align-self: start - margin-top: 2px - position: relative - color: var(--secondary-text-color) custom_fields: radar: - grid-area: radar - justify-self: start - width: var(--config-shape-size) - height: var(--config-shape-size) - border-radius: 50% - border: 1px solid rgba(128, 128, 128, 0.15) - background: rgba(128, 128, 128, 0.05) - position: relative - overflow: hidden - box-shadow: inset 0 2px 8px rgba(0,0,0,0.1) badge1: - position: absolute - top: 12px - right: | [[[ let btn_valid = variables.show_track_button !== false && variables.track_button && states[variables.track_button] && states[variables.track_button].state !== 'unknown' && states[variables.track_button].state !== 'unavailable'; return btn_valid ? '46px' : '12px'; ]]] - transition: right 0.3s ease-out - padding: 4px 10px - font-size: var(--config-font-badge) - letter-spacing: 0.5px - white-space: nowrap - font-weight: 600 - text-transform: uppercase - z-index: 5 badge2: - position: absolute - top: 45px - right: 12px - padding: 4px 10px - font-size: var(--config-font-badge) - letter-spacing: 0.5px - white-space: nowrap - opacity: 0.9 - font-weight: 500 - z-index: 5 track_button: - position: absolute - top: 11px - right: 12px - z-index: 10 - display: | [[[ let btn_valid = variables.show_track_button !== false && variables.track_button && states[variables.track_button] && states[variables.track_button].state !== 'unknown' && states[variables.track_button].state !== 'unavailable'; return btn_valid ? 'block' : 'none'; ]]] zone_map: - position: absolute - bottom: 0 - left: 0 - width: 100% - height: 42px - z-index: 1 tap_action: action: more-info label: | [[[ if (!entity) return 'Entity Setup Required'; let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable'; if (!range_valid) return '\u00A0'; let max_l = parseFloat(variables.max_supported_limit) || 6.0; let bm = parseInt(states[variables.range].state); let highest_zone = -1; if (!isNaN(bm)) { for(let i=23; i>=0; i--) { if((bm & (1<= 0 ? (highest_zone + 1) * 0.25 : max_l; return `Zone Limit: ${limit.toFixed(1)}m`; ]]] custom_fields: badge1: ' ' badge2: ' ' track_button: card: type: custom:button-card entity: '[[[ return variables.track_button ]]]' icon: mdi:crosshairs-gps show_name: false show_state: false styles: card: - width: 26px - height: 26px - border-radius: 50% - background: rgba(128, 128, 128, 0.1) - border: 1px solid rgba(128, 128, 128, 0.2) - box-shadow: 0 2px 4px rgba(0,0,0,0.1) - display: flex icon: - width: 16px - color: var(--primary-text-color) tap_action: action: call-service service: button.press service_data: entity_id: '[[[ return variables.track_button ]]]' radar: | [[[ let is_on = entity && entity.state === 'on'; let dist_valid = variables.show_distance !== false && variables.distance && states[variables.distance] && states[variables.distance].state !== 'unknown' && states[variables.distance].state !== 'unavailable'; let safe_dist = dist_valid ? parseFloat(states[variables.distance].state) : 0; let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable'; let bm = range_valid ? parseInt(states[variables.range].state) : 0; let max_r = parseFloat(variables.max_supported_limit) || 6.0; let highest_zone = -1; if (range_valid && !isNaN(bm)) { for(let i=23; i>=0; i--) { if((bm & (1<= 0 ? (highest_zone + 1) * 0.25 : max_r) : max_r; if (safe_dist > max_r) safe_dist = max_r; let raw_zone = Math.floor(safe_dist / 0.25); let is_zone_valid = range_valid ? ((bm & (1 << raw_zone)) !== 0) : true; let max_svg = 47.5; let range_pct = (range_val / max_r) * max_svg; let dist_pct = dist_valid ? ((safe_dist / max_r) * max_svg) : 0; let c_rgb = is_on ? '0, 229, 255' : '158, 158, 158'; let t_rgb = is_zone_valid ? c_rgb : '255, 82, 82'; let stroke_color = 'rgba(128,128,128,0.2)'; return ` ${is_on && dist_valid ? ` ` : ''} ${is_on ? `
` : ''} `; ]]] zone_map: | [[[ let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable'; if (!range_valid) return ''; let is_on = entity && entity.state === 'on'; let dist_valid = variables.show_distance !== false && variables.distance && states[variables.distance] && states[variables.distance].state !== 'unknown' && states[variables.distance].state !== 'unavailable'; let safe_dist = dist_valid ? parseFloat(states[variables.distance].state) : 0; let bm = parseInt(states[variables.range].state); if(isNaN(bm)) bm = 0; let max_r = parseFloat(variables.max_supported_limit) || 6.0; let visual_steps = parseInt(variables.zone_steps) || 12; safe_dist = Math.max(0, Math.min(safe_dist, max_r - 0.001)); let step_size = max_r / visual_steps; let tracked_visual_step = Math.floor(safe_dist / step_size); let total_raw_zones = Math.ceil(max_r / 0.25); let raw_per_step = total_raw_zones / visual_steps; let visual_array = Array(visual_steps).fill(false); for(let i=0; i= 0 && v_idx < visual_steps) visual_array[v_idx] = true; } } let zone_bars = `
`; for(let i=0; i
`; } zone_bars += ``; let l1 = (max_r * 0.25).toFixed(1) + 'm'; let l2 = (max_r * 0.50).toFixed(1) + 'm'; let l3 = (max_r * 0.75).toFixed(1) + 'm'; let l4 = max_r.toFixed(0) + 'm'; let labels = `
0m${l1}${l2}${l3}${l4}
`; return `
${labels}${zone_bars}
`; ]]] extra_styles: | [[[ let is_on = entity && entity.state === 'on'; let dist_valid = variables.show_distance !== false && variables.distance && states[variables.distance] && states[variables.distance].state !== 'unknown' && states[variables.distance].state !== 'unavailable' && !isNaN(parseFloat(states[variables.distance].state)); let safe_dist = dist_valid ? parseFloat(states[variables.distance].state) : 0; if (safe_dist > variables.max_supported_limit) safe_dist = variables.max_supported_limit; let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable' && !isNaN(parseInt(states[variables.range].state)); let bm = range_valid ? parseInt(states[variables.range].state) : 0; let raw_zone = Math.floor(safe_dist / 0.25); let is_zone_valid = range_valid ? ((bm & (1 << raw_zone)) !== 0) : true; let status_text = 'CLEAR'; if (!entity) { status_text = 'SETUP REQ'; } else if (is_on) { if (dist_valid) { status_text = `PRESENCE • ${safe_dist.toFixed(1)}m`; } else { status_text = 'PRESENCE'; } } let color = is_on ? (is_zone_valid ? '0, 229, 255' : '255, 82, 82') : '158, 158, 158'; let env_parts = []; let c_temp = '128, 128, 128'; let c_hum = '128, 128, 128'; let c_lux = '128, 128, 128'; if (variables.show_environment !== false && variables.temp && states[variables.temp]) { let st = states[variables.temp].state; if (st !== 'unknown' && st !== 'unavailable') { let v = parseFloat(st); if (!isNaN(v)) { env_parts.push(`${v.toFixed(1)}°C`); if (v < variables.temp_low) c_temp = '66, 165, 245'; else if (v < variables.temp_mid) c_temp = '255, 235, 59'; else if (v < variables.temp_high) c_temp = '255, 167, 38'; else c_temp = '239, 83, 80'; } } } if (variables.show_environment !== false && variables.humidity && states[variables.humidity]) { let st = states[variables.humidity].state; if (st !== 'unknown' && st !== 'unavailable') { let v = parseFloat(st); if (!isNaN(v)) { env_parts.push(`${v.toFixed(0)}%`); if (v < variables.hum_low) c_hum = '255, 167, 38'; else if (v <= variables.hum_high) c_hum = '66, 165, 245'; else c_hum = '255, 167, 38'; } } } if (variables.show_environment !== false && variables.lux && states[variables.lux]) { let st = states[variables.lux].state; if (st !== 'unknown' && st !== 'unavailable') { let v = parseFloat(st); if (!isNaN(v)) { env_parts.push(`${v.toFixed(0)}lx`); c_lux = v < variables.lux_min ? '120, 144, 156' : (v > variables.lux_max ? '255, 235, 59' : '212, 225, 87'); } } } let b2_text = env_parts.join(' • '); let display_b2 = env_parts.length > 0 ? 'block' : 'none'; let bg_gradient = `linear-gradient(90deg, rgba(${c_temp}, 0.15) 0%, rgba(${c_hum}, 0.15) 50%, rgba(${c_lux}, 0.2) 100%)`; return ` #card { --appliance-color: ${color}; } #badge1 { display: block; background: rgba(var(--appliance-color), 0.07); color: var(--primary-text-color); border-top: 1px solid var(--divider-color, rgba(128,128,128,0.2)); border-bottom: 1px solid var(--divider-color, rgba(128,128,128,0.2)); border-left: 2.5px solid rgb(var(--appliance-color)); border-radius: 6px !important; } #badge1::before { content: "${status_text}"; } #badge2 { display: ${display_b2}; background: ${bg_gradient}; color: var(--primary-text-color); border-top: 1px solid var(--divider-color, rgba(128,128,128,0.2)); border-bottom: 1px solid var(--divider-color, rgba(128,128,128,0.2)); border-left: 2.5px solid rgb(${c_temp}); border-right: 2.5px solid rgb(${c_lux}); border-radius: 6px !important; } #badge2::before { content: "${b2_text}"; } @keyframes radar-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; ]]] ```

665270583-e99d9c97-0201-489e-99b3-9506c5fa2cb7
Smoke detector card ```yaml type: custom:button-card entity: binary_sensor.aqara_smoke_detector_smoke name: Smoke Detector show_state: false show_label: true variables: sensor_density: sensor.aqara_smoke_detector_smoke_density sensor_battery: sensor.aqara_smoke_detector_battery show_bar: false theme_idle_colored: false heartbeat_color: '#4caf50' heartbeat_interval: 3s batt_red: 20 batt_orange: 40 batt_yellow: 70 dens_yellow: 0.1 dens_orange: 0.3 dens_red: 0.5 size_icon: 45px size_shape: 65px size_card_height: 95px font_primary: 15px font_secondary: 12px font_badge: 10px styles: card: - --config-icon-size: '[[[ return variables.size_icon ]]]' - --config-shape-size: '[[[ return variables.size_shape ]]]' - --config-card-height: '[[[ return variables.size_card_height ]]]' - --config-font-primary: '[[[ return variables.font_primary ]]]' - --config-font-secondary: '[[[ return variables.font_secondary ]]]' - --config-font-badge: '[[[ return variables.font_badge ]]]' - height: var(--config-card-height) !important - padding: 0px !important - overflow: hidden - position: relative - transition: background 0.5s ease grid: - padding: 12px 16px - height: 100% - box-sizing: border-box - grid-template-areas: '"i n" "i l"' - grid-template-columns: var(--config-shape-size) 1fr - grid-template-rows: auto auto - align-content: center - gap: 0px 12px - position: relative - z-index: 2 icon: - width: var(--config-icon-size) - height: var(--config-icon-size) - color: var(--primary-text-color) - z-index: 3 - animation: var(--anim-icon-shake) - transform-origin: center center - will-change: transform img_cell: - width: var(--config-shape-size) - height: var(--config-shape-size) - border-radius: 50% - border: 1px solid var(--divider-color, rgba(128,128,128,0.2)) !important - background: rgba(var(--appliance-color), 0.1) !important - position: relative - overflow: visible !important - justify-self: start - z-index: 2 name: - justify-self: start - font-size: var(--config-font-primary) - font-weight: 500 - align-self: end - margin-bottom: 2px - position: relative - z-index: 3 label: - justify-self: start - font-size: var(--config-font-secondary) - opacity: 0.7 - align-self: start - margin-top: 2px - position: relative - z-index: 3 custom_fields: bg_smoke: - position: absolute - inset: 0 - z-index: 0 - pointer-events: none - display: var(--display-smoke) heartbeat: - position: absolute - top: 10px - left: 10px - width: 6px - height: 6px - border-radius: 50% - background: var(--hb-color) - box-shadow: 0 0 6px var(--hb-color) - display: var(--display-heartbeat) - animation: hardware-blink var(--hb-interval) infinite - z-index: 5 badge1: - position: absolute - top: 10px - right: 10px - background: rgba(var(--appliance-color), 0.15) - color: var(--primary-text-color) - border-top: 1px solid rgba(128,128,128, 0.2) - border-bottom: 1px solid rgba(128,128,128, 0.2) - border-left: 2.5px solid rgb(var(--appliance-color)) - padding: 2px 10px - border-radius: 6px - font-size: var(--config-font-badge) - font-weight: 600 - text-transform: uppercase - letter-spacing: 0.5px - white-space: nowrap - z-index: 5 badge2: - position: absolute - top: 38px - right: 10px - color: var(--primary-text-color) - border-top: 1px solid rgba(128,128,128, 0.2) - border-bottom: 1px solid rgba(128,128,128, 0.2) - padding: 4px 8px - font-size: 10px - letter-spacing: 0.5px - white-space: nowrap - opacity: 0.9 - text-transform: uppercase - font-weight: 500 - border-radius: 6px - display: var(--display-badge2) - z-index: 5 bar: - position: absolute - bottom: 0 - left: 0 - height: 3.5px - width: var(--appliance-level) - background: rgb(var(--appliance-color)) - box-shadow: 0 0 8px rgb(var(--appliance-color)) - transition: width 0.5s ease - display: var(--display-bar) - z-index: 5 tap_action: action: more-info label: | [[[ let ent_smoke = entity ? entity.entity_id : null; if (!ent_smoke || !states[ent_smoke]) return 'Entity Setup Required'; return states[ent_smoke].state === 'on' ? 'Smoke Detected' : 'Monitoring'; ]]] icon: mdi:smoke-detector custom_fields: badge1: ' ' badge2: ' ' bar: ' ' heartbeat: ' ' bg_smoke: | [[[ return `
`; ]]] extra_styles: | [[[ let ent_smoke = entity ? entity.entity_id : null; let ent_bat = variables.sensor_battery; let ent_den = variables.sensor_density; let is_smoke = ent_smoke && states[ent_smoke] && states[ent_smoke].state === 'on'; let raw_bat = states[ent_bat] ? parseFloat(states[ent_bat].state) : NaN; let raw_den = states[ent_den] ? parseFloat(states[ent_den].state) : NaN; let theme_colored = variables.theme_idle_colored !== undefined ? variables.theme_idle_colored : false; let status = 'CLEAR'; let color = theme_colored ? '0, 229, 255' : '158, 158, 158'; let anim_shake = 'none'; let anim_strobe = 'none'; let display_smoke = 'none'; let display_heartbeat = 'block'; if (is_smoke) { status = 'SMOKE ALARM'; color = '244, 67, 54'; anim_shake = 'buzzer-shake 0.1s linear infinite'; anim_strobe = 'strobe-fade 0.8s ease-in-out infinite'; display_smoke = 'block'; display_heartbeat = 'none'; } let progress = isNaN(raw_bat) ? 100 : Math.max(0, Math.min(100, raw_bat)); let display_bar = (variables.show_bar !== false && !isNaN(raw_bat)) ? 'block' : 'none'; let c_bat = '76, 175, 80'; if (!isNaN(raw_bat)) { if (raw_bat <= (variables.batt_red || 20)) { c_bat = '244, 67, 54'; } else if (raw_bat <= (variables.batt_orange || 40)) { c_bat = '255, 152, 0'; } else if (raw_bat <= (variables.batt_yellow || 70)) { c_bat = '255, 235, 59'; } } let c_den = '76, 175, 80'; if (!isNaN(raw_den)) { if (raw_den >= (variables.dens_red || 0.5)) { c_den = '244, 67, 54'; } else if (raw_den >= (variables.dens_orange || 0.3)) { c_den = '255, 152, 0'; } else if (raw_den >= (variables.dens_yellow || 0.1)) { c_den = '255, 235, 59'; } } let b2_arr = []; let b2_text = ''; if (!isNaN(raw_bat)) b2_arr.push(`Bat ${Math.round(raw_bat)}%`); if (!isNaN(raw_den)) b2_arr.push(`Den ${raw_den}`); let display_badge2 = b2_arr.length > 0 ? 'block' : 'none'; if (b2_arr.length > 0) { b2_text = b2_arr.join(' • '); } let bg_badge2 = 'rgba(128,128,128,0.05)'; let b2_left = '1px solid rgba(128,128,128,0.2)'; let b2_right = '1px solid rgba(128,128,128,0.2)'; if (!isNaN(raw_bat) && !isNaN(raw_den)) { bg_badge2 = `linear-gradient(90deg, rgba(${c_bat}, 0.15) 30%, rgba(${c_den}, 0.2) 75%)`; b2_left = `2.5px solid rgb(${c_bat})`; b2_right = `2.5px solid rgb(${c_den})`; } else if (!isNaN(raw_bat)) { bg_badge2 = `rgba(${c_bat}, 0.15)`; b2_left = `2.5px solid rgb(${c_bat})`; } else if (!isNaN(raw_den)) { bg_badge2 = `rgba(${c_den}, 0.15)`; b2_right = `2.5px solid rgb(${c_den})`; } return ` #card { --appliance-color: ${color}; --appliance-level: ${progress}%; --anim-icon-shake: ${anim_shake}; --anim-cell-strobe: ${anim_strobe}; --display-smoke: ${display_smoke}; --display-bar: ${display_bar}; --display-heartbeat: ${display_heartbeat}; --display-badge2: ${display_badge2}; --hb-color: ${variables.heartbeat_color || '#4caf50'}; --hb-interval: ${variables.heartbeat_interval || '5s'}; } #badge1::before { content: "${status}"; } #badge2 { background: ${bg_badge2}; border-left: ${b2_left}; border-right: ${b2_right}; } #badge2::before { content: "${b2_text}"; } #img-cell::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background-color: rgba(var(--appliance-color), 0.5); box-shadow: 0 0 20px rgba(var(--appliance-color), 0.6); opacity: 0; animation: var(--anim-cell-strobe); pointer-events: none; will-change: opacity; } .smoke-plume { position: absolute; bottom: -40px; background: radial-gradient(circle at center, color-mix(in srgb, var(--primary-text-color) 40%, transparent) 0%, transparent 65%); border-radius: 50%; opacity: 0; will-change: transform, opacity; } .plume-1 { animation: drift-1 4s ease-in infinite; } .plume-2 { animation: drift-2 4.5s ease-in infinite; } .plume-3 { animation: drift-3 5s ease-in infinite; } .plume-4 { animation: drift-1 5.5s ease-in infinite; } @keyframes buzzer-shake { 0%, 100% { transform: translate3d(0, 0, 0); } 25% { transform: translate3d(-1px, 0.5px, 0) rotate(-1.5deg); } 75% { transform: translate3d(1px, -0.5px, 0) rotate(1.5deg); } } @keyframes strobe-fade { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } @keyframes hardware-blink { 0%, 8%, 100% { opacity: 0; } 4% { opacity: 1; } } @keyframes drift-1 { 0% { transform: translate3d(0, 10px, 0) scale(0.5); opacity: 0; } 30% { opacity: 0.7; } 100% { transform: translate3d(-15px, -110px, 0) scale(2.8); opacity: 0; } } @keyframes drift-2 { 0% { transform: translate3d(0, 10px, 0) scale(0.5); opacity: 0; } 30% { opacity: 0.6; } 100% { transform: translate3d(20px, -100px, 0) scale(3.2); opacity: 0; } } @keyframes drift-3 { 0% { transform: translate3d(0, 10px, 0) scale(0.5); opacity: 0; } 30% { opacity: 0.8; } 100% { transform: translate3d(-5px, -120px, 0) scale(3.0); opacity: 0; } } `; ]]] ```

665270603-0e21a7c6-cfbb-47fd-8f92-ea5fa3a7038f
Liquid card (Water) ```yaml type: custom:button-card entity: sensor.water_tank_level name: Water Tank show_icon: true show_name: true show_state: true icon: mdi:water variables: card_h: 150 circle_size: 100 styles: card: - height: '[[[ return variables.card_h + ''px'' ]]]' - position: relative - overflow: hidden - background: transparent - box-shadow: var(--ha-card-box-shadow, none) - border-radius: var(--ha-card-border-radius, 12px) - border: | [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; let rgb = level <= 20 ? "150, 29, 29" : "29, 130, 150"; return `1px solid rgba(${rgb}, 0.3)`; ]]] grid: - grid-template-areas: '"i" "s" "n"' - grid-template-columns: 1fr - grid-template-rows: min-content min-content min-content - height: 100% - align-content: center - justify-content: center - gap: '[[[ return (variables.circle_size * 0.02) + ''px'' ]]]' icon: - color: white - width: '[[[ return (variables.circle_size * 0.35) + ''px'' ]]]' - justify-self: center - filter: drop-shadow(0px 1px 3px rgba(0,0,0,0.8)) - position: relative - z-index: 3 state: - color: white - font-size: '[[[ return (variables.circle_size * 0.15) + ''px'' ]]]' - font-weight: bold - justify-self: center - text-shadow: 0px 1px 3px rgba(0,0,0,0.8) - position: relative - z-index: 3 name: - color: white - font-size: '[[[ return (variables.circle_size * 0.10) + ''px'' ]]]' - justify-self: center - text-shadow: 0px 1px 3px rgba(0,0,0,0.8) - position: relative - z-index: 3 custom_fields: glass_circle: - position: absolute - top: 50% - left: 50% - transform: translate(-50%, -50%) - width: '[[[ return variables.circle_size + ''px'' ]]]' - height: '[[[ return variables.circle_size + ''px'' ]]]' - border-radius: 50% - background: rgba(0, 0, 0, 0.25) - backdrop-filter: blur(6px) - -webkit-backdrop-filter: blur(6px) - border: 1px solid rgba(255, 255, 255, 0.15) - box-shadow: 0 4px 15px rgba(0,0,0,0.3) - z-index: 2 back_wave: - position: absolute - inset: 0 - z-index: 1 - pointer-events: none - display: |- [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; return level <= 0 ? "none" : "block"; ]]] front_wave: - position: absolute - inset: 0 - z-index: 1 - pointer-events: none - display: |- [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; return level <= 0 ? "none" : "block"; ]]] custom_fields: glass_circle: | [[[ return ``; ]]] back_wave: | [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; let rgb = level <= 20 ? "150, 29, 29" : "29, 130, 150"; let color = `rgba(${rgb}, 0.6)`; /* Draw SVG path */ let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z"; let svg = ``; /* Repeat the SVG 10 times */ let wave_row = svg.repeat(10); return `
${wave_row}
`; ]]] front_wave: | [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; let rgb = level <= 20 ? "150, 29, 29" : "29, 130, 150"; let color = `rgba(${rgb}, 1)`; /* Draw SVG path */ let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z"; let svg = ``; /* Repeat the SVG 10 times */ let wave_row = svg.repeat(10); return `
${wave_row}
`; ]]] extra_styles: | @keyframes scroll-left { 0% { transform: translateX(0); } 100% { transform: translateX(-120px); } } @keyframes scroll-right { 0% { transform: translateX(-120px); } 100% { transform: translateX(0); } } ```
Liquid card (Fuel) ```yaml type: custom:button-card entity: sensor.fuel_tank_level name: Fuel Tank show_icon: true show_name: true show_state: true icon: mdi:barrel variables: card_h: 150 circle_size: 100 styles: card: - height: '[[[ return variables.card_h + ''px'' ]]]' - position: relative - overflow: hidden - background: transparent - box-shadow: var(--ha-card-box-shadow, none) - border-radius: var(--ha-card-border-radius, 12px) - border: | [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; let rgb = level <= 20 ? "211, 47, 47" : "245, 124, 0"; return `1px solid rgba(${rgb}, 0.3)`; ]]] grid: - grid-template-areas: '"i" "s" "n"' - grid-template-columns: 1fr - grid-template-rows: min-content min-content min-content - height: 100% - align-content: center - justify-content: center - gap: '[[[ return (variables.circle_size * 0.02) + ''px'' ]]]' icon: - color: white - width: '[[[ return (variables.circle_size * 0.35) + ''px'' ]]]' - justify-self: center - filter: drop-shadow(0px 1px 3px rgba(0,0,0,0.8)) - position: relative - z-index: 3 state: - color: white - font-size: '[[[ return (variables.circle_size * 0.15) + ''px'' ]]]' - font-weight: bold - justify-self: center - text-shadow: 0px 1px 3px rgba(0,0,0,0.8) - position: relative - z-index: 3 name: - color: white - font-size: '[[[ return (variables.circle_size * 0.10) + ''px'' ]]]' - justify-self: center - text-shadow: 0px 1px 3px rgba(0,0,0,0.8) - position: relative - z-index: 3 custom_fields: glass_circle: - position: absolute - top: 50% - left: 50% - transform: translate(-50%, -50%) - width: '[[[ return variables.circle_size + ''px'' ]]]' - height: '[[[ return variables.circle_size + ''px'' ]]]' - border-radius: 50% - background: rgba(0, 0, 0, 0.25) - backdrop-filter: blur(6px) - -webkit-backdrop-filter: blur(6px) - border: 1px solid rgba(255, 255, 255, 0.15) - box-shadow: 0 4px 15px rgba(0,0,0,0.3) - z-index: 2 back_wave: - position: absolute - inset: 0 - z-index: 1 - pointer-events: none - display: >- [[[ return ((entity ? parseFloat(entity.state) || 0 : 0) <= 0) ? "none" : "block"; ]]] front_wave: - position: absolute - inset: 0 - z-index: 1 - pointer-events: none - display: >- [[[ return ((entity ? parseFloat(entity.state) || 0 : 0) <= 0) ? "none" : "block"; ]]] custom_fields: glass_circle: | [[[ return ``; ]]] back_wave: | [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; let rgb = level <= 20 ? "211, 47, 47" : "245, 124, 0"; let color = `rgba(${rgb}, 0.6)`; /* Draw SVG path */ let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z"; let svg = ``; /* Repeat the SVG 10 times */ let wave_row = svg.repeat(10); return `
${wave_row}
`; ]]] front_wave: | [[[ let level = entity ? parseFloat(entity.state) || 0 : 0; let rgb = level <= 20 ? "211, 47, 47" : "245, 124, 0"; let color = `rgba(${rgb}, 1)`; /* Draw SVG path */ let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z"; let svg = ``; /* Repeat the SVG 10 times */ let wave_row = svg.repeat(10); return `
${wave_row}
`; ]]] extra_styles: | @keyframes scroll-left { 0% { transform: translateX(0); } 100% { transform: translateX(-120px); } } @keyframes scroll-right { 0% { transform: translateX(-120px); } 100% { transform: translateX(0); } } ```
Liquid card (Battery/percentage) ```yaml type: custom:button-card entity: sensor.anasbox_battery_level name: Battery show_icon: true show_name: true show_state: true variables: card_h: 150 circle_size: 110 threshold_red: 20 threshold_orange: 50 threshold_green: 100 charger_entity: binary_sensor.anasbox_is_charging icon: | [[[ if (entity && entity.attributes && entity.attributes.icon) return entity.attributes.icon; let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0; let charger = variables.charger_entity && states[variables.charger_entity] ? states[variables.charger_entity] : null; let is_charging = charger ? ['on', 'charging', 'plugged'].includes(charger.state.toLowerCase()) : false; let rounded = Math.round(level / 10) * 10; if (is_charging) { if (rounded === 0) return "mdi:battery-charging-outline"; return `mdi:battery-charging-${rounded}`; } if (rounded === 100) return "mdi:battery"; if (rounded === 0) return "mdi:battery-outline"; return `mdi:battery-${rounded}`; ]]] styles: card: - height: '[[[ return variables.card_h + ''px'' ]]]' - position: relative - overflow: hidden - background: transparent - box-shadow: var(--ha-card-box-shadow, none) - border-radius: var(--ha-card-border-radius, 12px) - border: | [[[ let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0; let is_charging = variables.charger_entity && states[variables.charger_entity] ? ['on', 'charging', 'plugged'].includes(states[variables.charger_entity].state.toLowerCase()) : false; let rgb = "0, 255, 100"; if (is_charging) rgb = "0, 255, 255"; else if (level <= variables.threshold_red) rgb = "244, 67, 54"; else if (level <= variables.threshold_orange) rgb = "255, 152, 0"; return `1px solid rgba(${rgb}, 0.3)`; ]]] grid: - grid-template-areas: '"i" "s" "n"' - grid-template-columns: 1fr - grid-template-rows: min-content min-content min-content - height: 100% - align-content: center - justify-content: center - gap: '[[[ return (variables.circle_size * 0.02) + ''px'' ]]]' icon: - color: white - width: '[[[ return (variables.circle_size * 0.35) + ''px'' ]]]' - justify-self: center - filter: drop-shadow(0px 1px 3px rgba(0,0,0,0.8)) - position: relative - z-index: 3 state: - color: white - font-size: '[[[ return (variables.circle_size * 0.15) + ''px'' ]]]' - font-weight: bold - justify-self: center - text-shadow: 0px 1px 3px rgba(0,0,0,0.8) - position: relative - z-index: 3 name: - color: white - font-size: '[[[ return (variables.circle_size * 0.10) + ''px'' ]]]' - justify-self: center - text-shadow: 0px 1px 3px rgba(0,0,0,0.8) - position: relative - z-index: 3 custom_fields: glass_circle: - position: absolute - top: 50% - left: 50% - transform: translate(-50%, -50%) - width: '[[[ return variables.circle_size + ''px'' ]]]' - height: '[[[ return variables.circle_size + ''px'' ]]]' - border-radius: 50% - background: rgba(0, 0, 0, 0.25) - backdrop-filter: blur(6px) - -webkit-backdrop-filter: blur(6px) - border: 1px solid rgba(255, 255, 255, 0.15) - box-shadow: 0 4px 15px rgba(0,0,0,0.3) - z-index: 2 back_wave: - position: absolute - inset: 0 - z-index: 1 - pointer-events: none front_wave: - position: absolute - inset: 0 - z-index: 1 - pointer-events: none custom_fields: glass_circle: | [[[ return ``; ]]] back_wave: | [[[ let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0; let display_level = Math.max(level, 5); let is_charging = variables.charger_entity && states[variables.charger_entity] ? ['on', 'charging', 'plugged'].includes(states[variables.charger_entity].state.toLowerCase()) : false; let rgb = "46, 204, 113"; if (is_charging) rgb = "52, 152, 219"; else if (level <= variables.threshold_red) rgb = "231, 76, 60"; else if (level <= variables.threshold_orange) rgb = "243, 156, 18"; let color = `rgba(${rgb}, 0.6)`; let speed = is_charging ? "2s" : "4s"; let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z"; let svg = ``; let wave_row = svg.repeat(10); return `
${wave_row}
`; ]]] front_wave: | [[[ let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0; let display_level = Math.max(level, 5); let is_charging = variables.charger_entity && states[variables.charger_entity] ? ['on', 'charging', 'plugged'].includes(states[variables.charger_entity].state.toLowerCase()) : false; let rgb = "46, 204, 113"; if (is_charging) rgb = "52, 152, 219"; else if (level <= variables.threshold_red) rgb = "231, 76, 60"; else if (level <= variables.threshold_orange) rgb = "243, 156, 18"; let color = `rgba(${rgb}, 1)`; let speed = is_charging ? "1.5s" : "3s"; let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z"; let svg = ``; let wave_row = svg.repeat(10); return `
${wave_row}
`; ]]] extra_styles: | @keyframes scroll-left { 0% { transform: translateX(0); } 100% { transform: translateX(-120px); } } @keyframes scroll-right { 0% { transform: translateX(-120px); } 100% { transform: translateX(0); } } ```

665270619-e1f31ec9-da72-4c9f-bdfc-ed20abf2d10c
Mushroom light card with color temps quick toggles
>* after pasting this card, use the Find & Replace ALL feature in the card editor (CTRL+F) and Replace `light.CHANGE_ME` with your light entity, to change it everywhere at once. ```yaml type: custom:vertical-stack-in-card cards: - type: custom:mushroom-light-card entity: light.CHANGE_ME name: Light Card Name icon: mdi:led-strip-variant show_brightness_control: true show_color_control: true show_color_temp_control: true use_light_color: true card_mod: style: mushroom-light-brightness-control$: mushroom-slider$: | .slider { background: rgba(255, 255, 255, 0.05) !important; } .slider-track-active { box-shadow: inset 0 2px 4px rgba(0,0,0,0.15) !important; } .: | ha-card { background: none !important; border: none !important; box-shadow: none !important; padding-top: 10px !important; padding-bottom: 10px !important; --control-height: 38px; --control-border-radius: 19px; } mushroom-state-info { max-width: calc(100% - 140px) !important; } - type: custom:mushroom-chips-card alignment: end card_mod: style: | ha-card { position: absolute; top: 10px; right: 10px; background: none !important; border: none !important; box-shadow: none !important; width: max-content; pointer-events: none; z-index: 10; --chip-background: rgba(255, 255, 255, 0.05); --chip-box-shadow: none; --chip-border-width: 0px; --chip-spacing: 6px; --chip-padding: 0 10px; --chip-height: 38px; --chip-icon-size: 20px; } mushroom-template-chip { pointer-events: auto; } chips: - type: template entity: light.CHANGE_ME icon: mdi:weather-sunset icon_color: >- {% set temp = state_attr(entity, 'color_temp_kelvin') %} {% set mode = state_attr(entity, 'color_mode') %} {{ 'orange' if is_state(entity, 'on') and mode == 'color_temp' and temp != None and temp <= 3200 else 'disabled' }} tap_action: action: call-service service: light.turn_on target: entity_id: light.CHANGE_ME data: color_temp_kelvin: 2702 - type: template entity: light.CHANGE_ME icon: mdi:white-balance-sunny icon_color: >- {% set temp = state_attr(entity, 'color_temp_kelvin') %} {% set mode = state_attr(entity, 'color_mode') %} {{ 'amber' if is_state(entity, 'on') and mode == 'color_temp' and temp != None and 3200 < temp < 5000 else 'disabled' }} tap_action: action: call-service service: light.turn_on target: entity_id: light.CHANGE_ME data: color_temp_kelvin: 4000 - type: template entity: light.CHANGE_ME icon: mdi:snowflake icon_color: >- {% set temp = state_attr(entity, 'color_temp_kelvin') %} {% set mode = state_attr(entity, 'color_mode') %} {{ 'light-blue' if is_state(entity, 'on') and mode == 'color_temp' and temp != None and temp >= 5000 else 'disabled' }} tap_action: action: call-service service: light.turn_on target: entity_id: light.CHANGE_ME data: color_temp_kelvin: 6535 card_mod: style: | ha-card { position: relative; } ```
--- [paypal_me_shield]: https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white [paypal_me]: https://paypal.me/anasboxsupport [revolut_me_shield]: https://img.shields.io/badge/revolut-FFFFFF?style=for-the-badge&logo=revolut&logoColor=black [revolut_me]: https://revolut.me/anas4e [ko_fi_shield]: https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white [ko_fi_me]: https://ko-fi.com/anasbox [buy_me_coffee_shield]: https://img.shields.io/badge/Buy%20Me%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black [buy_me_coffee_me]: https://www.buymeacoffee.com/anasbox [patreon_shield]: https://img.shields.io/badge/patreon-404040?style=for-the-badge&logo=patreon&logoColor=white [patreon_me]: https://patreon.com/AnasBox