{ "version": 1, "minor_version": 1, "key": "lovelace.lovelace", "data": { "config": { "views": [ { "type": "sections", "max_columns": 4, "title": "Main", "path": "main-home", "icon": "mdi:home", "sections": [ { "type": "grid", "cards": [ { "type": "custom:stack-in-card", "mode": "vertical", "keep": { "outer_padding": false, "margin": true }, "cards": [ { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1", "icon_color": "{{states('sensor.livingroom_temp_color_no_rgb')}}", "icon": "mdi:thermometer", "use_entity_picture": true, "double_tap_action": { "action": "none" }, "hold_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unavailable') %}\n -\n{% elif is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unknown') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1')}}°\n{% endif %}" }, { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2", "icon_color": "light-blue", "icon": "mdi:water-percent", "name": "", "use_entity_picture": true, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2','unavailable') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2')}}%\n{% endif %}" }, { "type": "template", "entity": "sensor.xiaomi_cn_2005161482_va3_hcho_density_p_3_11", "icon_color": "light-green", "icon": "mdi:air-filter", "name": "", "use_entity_picture": true, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.xiaomi_cn_2005161482_va3_hcho_density_p_3_11','unavailable') %}\n -\n{% else %}\n {{states('sensor.xiaomi_cn_2005161482_va3_hcho_density_p_3_11')}}%\n{% endif %}" } ], "alignment": "center" }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:lightbulb-group", "content": "{% if is_state('sensor.lights_of_count','0') %}\n \n{% else %}\n {{states('sensor.lights_of_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.lights_of_count')|float %}\n{% if state <= 0 %} grey\n{% else %} amber\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.lights_of_count" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:air-conditioner", "content": "{% if is_state('sensor.aircondition_of_count','0') %}\n \n{% else %}\n {{states('sensor.aircondition_of_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.aircondition_of_count')|float %}\n{% if state <= 0 %} grey\n{% else %} amber\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.aircondition_of_count" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:water", "content": "{% if is_state('sensor.water_damage_count','0') %}\n \n{% else %}\n {{states('sensor.water_damage_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.water_damage_count')|float %}\n{% if state <= 0 %} grey\n{% else %} blue\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.water_damage_count" } ], "alignment": "center" }, { "type": "custom:swipe-card", "mode": "vertical", "keep": { "outer_padding": false, "margin": true, "box_shadow": false, "background": false }, "cards": [ { "type": "horizontal-stack", "cards": [ { "type": "custom:mushroom-entity-card", "card_mod": { "style": "ha-card{\n box-shadow: none;\n }\n" }, "entity": "input_boolean.on_state", "double_tap_action": { "action": "none" }, "icon": "mdi:home", "icon_color": "green", "layout": "vertical", "hold_action": { "action": "none" }, "tap_action": { "action": "navigate", "navigation_path": "main-home" }, "primary_info": "none", "secondary_info": "name", "name": "首页" }, { "type": "custom:mushroom-entity-card", "card_mod": { "style": "ha-card{\n box-shadow: none;\n }\n" }, "entity": "switch.cuco_cn_2006579195_v3_on_p_2_1", "icon": "mdi:server", "icon_color": "light-blue", "layout": "vertical", "primary_info": "none", "secondary_info": "name", "tap_action": { "action": "navigate", "navigation_path": "home-server" }, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "name": "机房" }, { "type": "custom:mushroom-entity-card", "card_mod": { "style": "ha-card{\n box-shadow: none;\n }\n" }, "entity": "light.quan_wu_zhao_ming", "icon_color": "yellow", "secondary_info": "name", "layout": "vertical", "name": "Lights", "double_tap_action": { "action": "none" }, "hold_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "primary_info": "none", "icon": "mdi:lamps" } ] } ] } ], "card_mod": { "style": "ha-card {\n background-color: rgba(255, 255, 255, 0) !important;\n box-shadow: none !important;\n padding: 2px 0px 2px 0px;\n}\n" } } ], "column_span": 4 }, { "type": "grid", "cards": [ { "type": "custom:mushroom-title-card", "title": "Light" }, { "type": "custom:button-card", "entity": "light.quan_wu_zhao_ming", "show_icon": true, "show_name": true, "show_state": true, "show_label": true, "name": "灯光状态", "icon": "mdi:lightbulb-group", "state_display": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n \n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n const percentage = allLeafLights.length > 0 ? Math.round((onLights.length / allLeafLights.length) * 100) : 0;\n \n return `${percentage}%`;\n]]]\n", "label": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n \n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return '所有灯光已关闭';\n } else {\n return `${onLights.length}/${allLeafLights.length} 盏灯亮着`;\n }\n]]]\n", "styles": { "card": [ { "height": "80px" }, { "background": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n const percentage = allLeafLights.length > 0 ? (onLights.length / allLeafLights.length) : 0;\n \n // 胶囊形状背景\n if (percentage === 0) {\n // 全关状态 - 深色胶囊\n return 'linear-gradient(145deg, rgba(35,45,65,0.95), rgba(25,35,55,0.9))';\n } else {\n // 进度条效果 - 亮色表示开启比例\n const progressPercent = percentage * 100;\n return `\n linear-gradient(to right, \n rgba(255,210,60,0.8) 0%, \n rgba(255,190,40,0.9) ${progressPercent}%, \n rgba(50,70,110,0.3) ${progressPercent}%, \n rgba(35,55,95,0.4) 100%\n )\n `;\n }\n]]]\n" }, { "border-radius": "45px !important" }, { "box-shadow": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n const percentage = allLeafLights.length > 0 ? (onLights.length / allLeafLights.length) : 0;\n \n if (percentage === 0) {\n return 'inset 3px 3px 6px rgba(0,0,0,0.4), inset -3px -3px 6px rgba(80,100,140,0.2), 0 2px 8px rgba(0,0,0,0.3)';\n } else {\n return 'inset 2px 2px 4px rgba(0,0,0,0.3), inset -2px -2px 4px rgba(255,255,255,0.1), 0 6px 20px rgba(255,190,40,0.4)';\n }\n]]]\n" }, { "border": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return '1px solid rgba(70,90,130,0.4)';\n } else {\n return '1px solid rgba(255,190,40,0.6)';\n }\n]]]\n" }, { "padding": "12px 20px" }, { "display": "flex" }, { "align-items": "center" }, { "position": "relative" }, { "overflow": "hidden" } ], "grid": [ { "grid-template-areas": "\"icon name state\" \"icon label label\"" }, { "grid-template-columns": "min-content 1fr min-content" }, { "grid-template-rows": "1fr 1fr" }, { "gap": "0px 12px" } ], "icon": [ { "width": "50px" }, { "height": "50px" }, { "grid-area": "icon" }, { "color": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'rgba(140,160,200,0.7)';\n } else {\n return 'rgba(255,220,60,1)';\n }\n]]]\n" }, { "filter": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'none';\n } else {\n return 'drop-shadow(0 0 12px rgba(255,220,60,0.8))';\n }\n]]]\n" } ], "name": [ { "font-size": "15px" }, { "font-weight": 700 }, { "color": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'rgba(180,200,240,0.9)';\n } else {\n return 'rgba(255,255,255,1)';\n }\n]]]\n" }, { "grid-area": "name" }, { "align-self": "end" }, { "justify-self": "start" }, { "text-shadow": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'none';\n } else {\n return '0 1px 3px rgba(0,0,0,0.5)';\n }\n]]]\n" } ], "state": [ { "font-size": "22px" }, { "font-weight": "bold" }, { "color": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'rgba(160,180,220,0.9)';\n } else {\n return 'rgba(255,240,150,1)';\n }\n]]]\n" }, { "grid-area": "state" }, { "align-self": "end" }, { "justify-self": "end" }, { "text-shadow": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'none';\n } else {\n return '0 0 12px rgba(255,220,60,0.7)';\n }\n]]]\n" } ], "label": [ { "font-size": "13px" }, { "font-weight": 600 }, { "color": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'rgba(160,180,220,0.9)';\n } else {\n return 'rgba(255,255,240,1)';\n }\n]]]\n" }, { "grid-area": "label" }, { "align-self": "start" }, { "justify-self": "start" }, { "margin-top": "2px" }, { "text-shadow": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n \n if (onLights.length === 0) {\n return 'none';\n } else {\n return '0 1px 2px rgba(0,0,0,0.4)';\n }\n]]]\n" } ] }, "custom_fields": { "progress_indicator": "[[[\n const getAllLightEntities = (entityId) => {\n const entityState = states[entityId];\n if (!entityState) return [];\n if (entityState.attributes && entityState.attributes.entity_id) {\n const childEntities = entityState.attributes.entity_id;\n let allLights = [];\n childEntities.forEach(childId => {\n allLights = allLights.concat(getAllLightEntities(childId));\n });\n return allLights;\n } else {\n return [entityId];\n }\n };\n const allLeafLights = getAllLightEntities('light.quan_wu_zhao_ming');\n const onLights = allLeafLights.filter(eid => states[eid] && states[eid].state === 'on');\n const percentage = allLeafLights.length > 0 ? (onLights.length / allLeafLights.length) : 0;\n \n if (percentage === 0) {\n return '
';\n } else {\n const progressWidth = percentage * 100;\n return `\n \n `;\n }\n]]]\n" }, "styles_css": "ha-card {\n position: relative;\n overflow: hidden;\n}\n.custom-fields {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 0;\n}\n" }, { "type": "vertical-stack", "cards": [ { "type": "custom:bubble-card", "card_type": "separator", "icon": "mdi:ceiling-light-multiple", "card_layout": "large", "rows": "0.8" } ] }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1187112198_xsx340_s_2", "name": "客厅主灯", "use_light_color": false, "icon": "mdi:ceiling-light-multiple", "icon_color": "accent", "show_brightness_control": true, "show_color_temp_control": true, "show_color_control": false }, { "type": "custom:mushroom-light-card", "entity": "light.shhf_cn_1129134246_sflt11_s_2_light", "name": "餐桌", "icon_color": "orange", "fill_container": true, "show_brightness_control": true, "use_light_color": false, "show_color_temp_control": true, "show_color_control": false, "icon": "mdi:ceiling-fan-light", "primary_info": "name", "grid_options": { "columns": 6, "rows": 2 } }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1186735998_xsx340_s_2", "name": "主卧", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "show_color_control": false }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1186772227_xsx340_s_2", "name": "次卧灯", "use_light_color": false, "show_brightness_control": true, "show_color_temp_control": true, "show_color_control": false, "collapsible_controls": false }, { "type": "custom:mushroom-light-card", "entity": "light.opple_cn_2005385416_moat_s_2_light", "name": "阳台灯", "icon": "mdi:light-recessed", "icon_color": "accent", "fill_container": true, "show_brightness_control": true, "show_color_temp_control": true }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1186744390_xsx340_s_2", "name": "书房灯", "icon": "mdi:ceiling-light", "icon_color": "light-blue", "fill_container": true, "show_brightness_control": true, "show_color_temp_control": true }, { "type": "custom:mushroom-light-card", "entity": "light.panpan_cn_876603548_y18_s_3_light", "icon": "", "show_brightness_control": false, "show_color_temp_control": false, "use_light_color": false, "show_color_control": false, "grid_options": { "columns": 12, "rows": 2 } } ], "column_span": 1 }, { "type": "grid", "cards": [ { "type": "custom:mushroom-title-card", "title": "空调" }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "thermostat", "entity": "climate.qdhkl_cn_2113954983_b19c", "show_current_as_primary": false, "features": [ { "type": "climate-hvac-modes" } ], "grid_options": { "columns": 12, "rows": 6 }, "theme": "Mushroom Shadow" }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "climate.qdhkl_cn_2113954983_b19c", "icon": "mdi:power" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '8px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '28px' %}\n\n /* 3. SIZING */\n {% set icon_size = '25px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '6px' %} \n {% set border_radius = '6px' %} \n {% set border_thickness = '0.5px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#b86836' %} \n {% set active_icon = '#d4f228' %}\n {% set active_text = 'white' %}\n {% set active_border = 'transparent' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'pulse' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state != 'off' %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } } ] }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-climate-card", "entity": "climate.qdhkl_cn_2113955096_b19c", "show_temperature_control": true, "collapsible_controls": true, "hvac_modes": [ "heat", "cool" ] }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "climate.qdhkl_cn_2113955096_b19c", "icon": "mdi:power" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '4px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '4px' %}\n\n /* 3. SIZING */\n {% set icon_size = '22px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '2px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0.5px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#b86836' %} \n {% set active_icon = '#d4f228' %}\n {% set active_text = 'white' %}\n {% set active_border = 'transparent' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'pulse' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state != 'off' %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } } ], "grid_options": { "columns": 6 } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-climate-card", "entity": "climate.qdhkl_cn_2113966364_b19c", "show_temperature_control": true, "collapsible_controls": true, "hvac_modes": [ "heat", "cool" ] }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "climate.qdhkl_cn_2113966364_b19c", "icon": "mdi:power" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '4px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '4px' %}\n\n /* 3. SIZING */\n {% set icon_size = '22px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '2px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0.5px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#b86836' %} \n {% set active_icon = '#d4f228' %}\n {% set active_text = 'white' %}\n {% set active_border = 'transparent' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'pulse' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state != 'off' %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } } ], "grid_options": { "columns": 6 } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-climate-card", "entity": "climate.qdhkl_cn_2113955084_b19c", "show_temperature_control": true, "collapsible_controls": true, "fill_container": false, "grid_options": { "columns": 12, "rows": 1 }, "hvac_modes": [ "heat", "cool" ] }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "climate.qdhkl_cn_2113955084_b19c", "icon": "mdi:power" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '4px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '4px' %}\n\n /* 3. SIZING */\n {% set icon_size = '22px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '2px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0.5px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#b86836' %} \n {% set active_icon = '#d4f228' %}\n {% set active_text = 'white' %}\n {% set active_border = 'transparent' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'pulse' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state != 'off' %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } } ] } ] }, { "type": "grid", "cards": [ { "type": "custom:mushroom-title-card", "title": "Devices" } ], "column_span": 4 }, { "type": "grid", "cards": [ { "type": "custom:mushroom-fan-card", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "icon_animation": true, "fill_container": false, "show_percentage_control": true, "show_oscillate_control": true, "show_direction_control": false, "collapsible_controls": false }, { "type": "custom:mushroom-fan-card", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "name": "风扇", "icon": "", "icon_animation": true, "show_percentage_control": true, "show_oscillate_control": false, "show_direction_control": true }, { "type": "custom:mushroom-fan-card", "entity": "fan.xiaomi_cn_2005161482_va3_s_2_air_purifier", "name": "空气净化器", "icon_animation": true, "fill_container": false, "show_percentage_control": true, "show_oscillate_control": false, "show_direction_control": false, "collapsible_controls": false, "grid_options": { "columns": 12, "rows": 2 } }, { "type": "custom:mushroom-cover-card", "entity": "cover.panpan_cn_876603548_y18_s_2_airer", "name": "晾衣架", "show_buttons_control": true, "show_position_control": false, "grid_options": { "columns": 12, "rows": 2 } } ] } ], "header": { "layout": "responsive", "badges_position": "bottom", "badges_wrap": "wrap" }, "background": { "opacity": 80, "alignment": "center", "size": "cover", "repeat": "repeat", "attachment": "fixed" }, "cards": [], "theme": "ios-dark-mode-light-blue", "visible": [ { "user": "7a6c93d08acc4692bfd561154bb386df" }, { "user": "7809f2c31fda449b8e7c5a0d2eaf5fd5" } ] }, { "type": "sections", "max_columns": 4, "title": "home-server", "path": "home-server", "icon": "mdi:server", "theme": "Mushroom Shadow", "sections": [ { "type": "grid", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "input_boolean.on_state", "icon": "mdi:home", "tap_action": { "action": "navigate", "navigation_path": "/lovelace/main-home" }, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "name": "首页", "primary_info": "none", "secondary_info": "name", "fill_container": false, "layout": "horizontal", "grid_options": { "columns": 6, "rows": 1 }, "icon_color": "green", "card_mod": { "style": "ha-card{\nbox-shadow: none;\n}\n" } }, { "type": "custom:mushroom-entity-card", "entity": "sensor.pan_ke_feng_de_iphone_battery_level", "tap_action": { "action": "more-info" }, "icon": "", "icon_color": "white", "primary_info": "name", "secondary_info": "none", "name": "Pan's Phone", "grid_options": { "rows": 1 }, "card_mod": { "style": { ".": "ha-card {\n /* ====== USER SETTINGS ===== */\n {% set charging_entity =\n 'binary_sensor.anasbox_is_charging' %} \n /* ========================= */\n\n /* ======= FONT SETTINGS ======= */\n --card-primary-font-size: 15px !important;\n --card-secondary-font-size: 12px !important;\n --card-primary-font-weight: bold !important;\n\n /* --- LOGIC --- */\n {% set level = states(config.entity) | float(0) %}\n {% set is_charging = is_state(charging_entity, 'on') %}\n \n /* 1. Determine Color */\n {% if is_charging %}\n {% set color = '0, 255, 255' %} /* Cyan (Charging) */\n {% elif level <= 20 %}\n {% set color = '244, 67, 54' %} /* Red */\n {% elif level <= 60 %}\n {% set color = '255, 152, 0' %} /* Orange */\n {% else %}\n {% set color = '0, 255, 100' %} /* Green */\n {% endif %}\n\n /* --- PASS VARIABLES TO CSS --- */\n --custom-level: {{ level }}%;\n --custom-color: rgba({{ color }}, 0.8);\n --custom-bubble: {{ 'block' if is_charging else 'none' }};\n \n /* Icon Glow */\n --custom-icon-shadow: {{ '0 0 15px rgba(' ~ color ~ ', 0.6)' if is_charging else 'none' }};\n \n /* Text Color */\n --text-color: {{ 'rgba(' ~ color ~ ', 1)' if level < 100 else 'rgba(255,255,255,0.7)' }};\n\n /* --- CARD STYLING --- */\n background: #1c1c1c !important;\n border: none !important;\n border-radius: 12px;\n position: relative;\n overflow: hidden;\n transition: all 0.5s ease;\n \n /* Ambient Glow behind the liquid */\n background-image: radial-gradient(circle at 24px 24px, rgba({{ color }}, 0.15) 0%, transparent 60%) !important;\n}\n\n/* Icon Styling */\nmushroom-shape-icon {\n --icon-size: 45px;\n display: flex;\n padding-right: 10px;\n padding-bottom: 5px;\n}\n\n/* --- PERCENTAGE BADGE (Top Right) --- */\nha-card::before {\n content: '{{ level | round(0) }}%';\n position: absolute;\n top: 12px; right: 12px;\n font-size: 1rem; font-weight: 700;\n color: var(--text-color);\n background: rgba(0, 0, 0, 0.3);\n border: 1px solid rgba(255, 255, 255, 0.1);\n padding: 2px 6px; border-radius: 4px;\n}\n\n/* --- PROGRESS BAR TRACK --- */\nha-card::after {\n content: '';\n position: absolute;\n bottom: 0; left: 0;\n height: 4px;\n width: {{ level }}%;\n background: linear-gradient(90deg, transparent, rgb({{ color }}));\n box-shadow: 0 0 10px rgb({{ color }});\n transition: width 0.5s ease;\n}\n", "mushroom-shape-icon$": ".shape {\n /* --- LOGIC INJECTION --- */\n --liquid-level: var(--custom-level);\n --liquid-color: var(--custom-color);\n --bubble-display: var(--custom-bubble);\n \n /* Container Setup */\n background: rgba(255, 255, 255, 0.05) !important;\n overflow: hidden !important; /* Keeps the liquid inside the circle */\n position: relative;\n border: 1px solid rgba(255,255,255,0.1);\n box-shadow: var(--custom-icon-shadow) !important;\n}\n\n/* THE LIQUID (Wavy Fill) */\n.shape::before {\n content: '';\n position: absolute;\n left: -50%;\n width: 200%;\n height: 200%;\n \n /* The top is calculated based on battery level (100% - level) */\n top: calc(100% - var(--liquid-level));\n \n background: var(--liquid-color);\n border-radius: 40%; /* Creates the \"Wave\" shape when rotated */\n \n /* The Wave Animation */\n animation: liquid-wave 6s linear infinite;\n opacity: 0.8;\n}\n\n/* CHARGING BUBBLES */\n.shape::after {\n content: '';\n display: var(--bubble-display);\n position: absolute;\n inset: 0;\n background-image: \n radial-gradient(2px 2px at 20% 80%, rgba(255,255,255,0.8), transparent),\n radial-gradient(2px 2px at 50% 70%, rgba(255,255,255,0.8), transparent),\n radial-gradient(3px 3px at 80% 90%, rgba(255,255,255,0.8), transparent);\n background-size: 100% 100%;\n animation: bubbles-rise 0.7s linear infinite;\n}\n\n/* Ensure the MDI Icon sits on top of the liquid */\nha-icon {\n position: relative;\n z-index: 2;\n /* Blend the icon slightly so it looks submerged */\n mix-blend-mode: overlay; \n color: white !important;\n}\n\n/* --- ANIMATIONS --- */\n@keyframes liquid-wave {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n@keyframes bubbles-rise {\n 0% { transform: translateY(10px); opacity: 0; }\n 50% { opacity: 1; }\n 100% { transform: translateY(-20px); opacity: 0; }\n}\n" } } } ], "column_span": 4 }, { "type": "grid", "cards": [ { "type": "custom:mushroom-title-card", "title": "Hello Mother Fucker", "alignment": "center" }, { "square": false, "type": "grid", "cards": [ { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "sensor.xiaomi_cn_blt_3_1ni9qhv584c03_mini_temperature_p_2_1001", "tap_action": { "action": "more-info" }, "icon": "mdi:thermometer", "name": "温度", "primary_info": "state", "secondary_info": "name", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== CONFIG ========== #}\n {# == Updated: entity auto generated == #}\n {% set temp = states(config.entity) | float(0) %}\n\n {# ------------------------------------------- #}\n {# TEMPERATURE → COLOR + EFFECT PRESETS #}\n {# ------------------------------------------- #}\n\n {# DEFAULTS (will be overridden by ranges) #}\n {% set rgb = '0,140,255' %}\n {% set anim = 'temp-cold-breathe' %}\n {% set glow_anim = 'temp-cold-glow' %}\n {% set halo_anim = 'temp-cold-halo' %}\n {% set duration = 4.0 %}\n {% set intensity = 0.5 %}\n\n {# RANGES / COLORS #}\n {# You can change temp numbers below if needed #}\n\n {% if temp < 16 %}\n {# BLUE #}\n {% set rgb = '0,140,255' %}\n {% set anim = 'temp-cold-breathe' %}\n {% set glow_anim = 'temp-cold-glow' %}\n {% set halo_anim = 'temp-cold-halo' %}\n {% set duration = 4.4 %}\n {% set intensity = 0.4 %}\n\n {% elif temp < 18 %}\n {# YELLOW #}\n {% set rgb = '255,210,40' %}\n {% set anim = 'temp-cool-wave' %}\n {% set glow_anim = 'temp-cool-glow' %}\n {% set halo_anim = 'temp-cool-halo' %}\n {% set duration = 3.4 %}\n {% set intensity = 0.55 %}\n\n {% elif temp < 20 %}\n {# ORANGE #}\n {% set rgb = '255,150,40' %}\n {% set anim = 'temp-comfy-breathe' %}\n {% set glow_anim = 'temp-comfy-glow' %}\n {% set halo_anim = 'temp-comfy-halo' %}\n {% set duration = 3.0 %}\n {% set intensity = 0.6 %}\n\n {% elif temp < 22 %}\n {# DARK ORANGE #}\n {% set rgb = '255,115,20' %}\n {% set anim = 'temp-warm-pulse' %}\n {% set glow_anim = 'temp-warm-glow' %}\n {% set halo_anim = 'temp-warm-halo' %}\n {% set duration = 2.4 %}\n {% set intensity = 0.8 %}\n\n {% else %}\n {# RED #}\n {% set rgb = '255,40,40' %}\n {% set anim = 'temp-hot-shimmer' %}\n {% set glow_anim = 'temp-hot-glow' %}\n {% set halo_anim = 'temp-hot-halo' %}\n {% set duration = 2.0 %}\n {% set intensity = 1.0 %}\n {% endif %}\n\n {# Apply variables #}\n --temp-rgb: {{ rgb }};\n --temp-intensity: {{ intensity }};\n --shape-animation: {{ anim }} {{ duration }}s ease-in-out infinite;\n --temp-glow-animation: {{ glow_anim }} {{ (duration * 0.9) | round(2) }}s ease-in-out infinite;\n --temp-halo-animation: {{ halo_anim }} {{ (duration * 1.15) | round(2) }}s ease-in-out infinite;\n\n opacity: 1;\n\n /* Icon color follows the temperature */\n --icon-color: rgba({{ rgb }}, 1);\n\n /* KILL THE THEME BLUE & MAKE SHAPE NEUTRAL */\n background-color: rgba(77, 77, 77,0.1) !important;\n box-shadow: none !important;\n border: 1px solid rgba(255,255,255,0.06);\n\n position: relative;\n transform-origin: 50% 60%;\n animation: var(--shape-animation);\n}\n\n/* Glow layers */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n inset: -8px;\n animation: var(--temp-glow-animation);\n}\n\n.shape::after {\n inset: -22px;\n animation: var(--temp-halo-animation);\n mix-blend-mode: screen;\n}\n\n/* ========== COLD ========== */\n@keyframes temp-cold-breathe {\n 0% { transform: scale(0.96); }\n 50% { transform: scale(1.03); }\n 100% { transform: scale(0.96); }\n}\n\n@keyframes temp-cold-glow {\n 0% {\n box-shadow:\n 0 0 20px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 6 rgba(var(--temp-rgb), 0.55);\n }\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(var(--temp-rgb), 0.95),\n 0 0 50px 10px rgba(var(--temp-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 20px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 6 rgba(var(--temp-rgb), 0.55);\n }\n}\n\n@keyframes temp-cold-halo {\n 0% {\n box-shadow:\n 0 0 80px 20px rgba(var(--temp-rgb), 0.35),\n 0 -20px 80px -14px rgba(220, 240, 255, 0.55);\n }\n 50% {\n box-shadow:\n 0 0 130px 36px rgba(var(--temp-rgb), 0.5),\n 0 -34px 100px -8px rgba(240, 250, 255, 0.8);\n }\n 100% {\n box-shadow:\n 0 0 80px 20px rgba(var(--temp-rgb), 0.35),\n 0 -20px 80px -14px rgba(220, 240, 255, 0.55);\n }\n}\n\n/* ========== COOL ========== */\n@keyframes temp-cool-wave {\n 0% { transform: translateX(0); }\n 25% { transform: translateX(-1px); }\n 50% { transform: translateX(1px) translateY(-1px); }\n 75% { transform: translateX(-1px); }\n 100% { transform: translateX(0); }\n}\n\n@keyframes temp-cool-glow {\n 0% {\n box-shadow:\n 0 0 22px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 4 rgba(var(--temp-rgb), 0.7);\n }\n 50% {\n box-shadow:\n 0 0 28px 2 rgba(var(--temp-rgb), 0.95),\n 0 0 48px 12px rgba(var(--temp-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 22px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 4 rgba(var(--temp-rgb), 0.7);\n }\n}\n\n@keyframes temp-cool-halo {\n 0% {\n box-shadow:\n 0 0 90px 26px rgba(var(--temp-rgb), 0.35),\n 0 18px 80px -12px rgba(0, 220, 255, 0.35);\n }\n 50% {\n box-shadow:\n 0 0 140px 42px rgba(var(--temp-rgb), 0.45),\n 0 30px 110px -10px rgba(0, 255, 255, 0.5);\n }\n 100% {\n box-shadow:\n 0 0 90px 26px rgba(var(--temp-rgb), 0.35),\n 0 18px 80px -12px rgba(0, 220, 255, 0.35);\n }\n}\n\n/* ========== COMFY ========== */\n@keyframes temp-comfy-breathe {\n 0% { transform: scale(0.98); }\n 50% { transform: scale(1.05); }\n 100% { transform: scale(0.98); }\n}\n\n@keyframes temp-comfy-glow {\n 50% {\n box-shadow:\n 0 0 26px 4 rgba(var(--temp-rgb), 0.9),\n 0 0 42px 10px rgba(var(--temp-rgb), 0.85);\n }\n}\n\n@keyframes temp-comfy-halo {\n 50% {\n box-shadow:\n 0 0 120px 40px rgba(var(--temp-rgb), 0.45),\n 0 26px 80px -10px rgba(180,255,200,0.5);\n }\n}\n\n/* ========== WARM ========== */\n@keyframes temp-warm-pulse {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.07); }\n 100% { transform: scale(1); }\n}\n\n@keyframes temp-warm-glow {\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(var(--temp-rgb), 0.95),\n 0 0 54px 14px rgba(var(--temp-rgb), 0.9);\n }\n}\n\n@keyframes temp-warm-halo {\n 50% {\n box-shadow:\n 0 0 140px 48px rgba(var(--temp-rgb), 0.55),\n 0 26px 100px -10px rgba(255,210,150,0.5);\n }\n}\n\n/* ========== HOT ========== */\n@keyframes temp-hot-shimmer {\n 0% { transform: scale(1); filter: blur(0); }\n 50% { transform: scale(1.08); filter: blur(0.6px); }\n 100% { transform: scale(1); filter: blur(0); }\n}\n\n@keyframes temp-hot-glow {\n 50% {\n box-shadow:\n 0 0 34px 6 rgba(var(--temp-rgb), 1),\n 0 0 62px 14px rgba(var(--temp-rgb), 0.95);\n }\n}\n\n@keyframes temp-hot-halo {\n 50% {\n box-shadow:\n 0 0 160px 60px rgba(var(--temp-rgb), 0.6),\n 0 34px 120px -12px rgba(255,150,100,0.6);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 48px;\n --icon-color: rgba(var(--hum-rgb),1) !important;\n display: flex;\n margin: -16px 0 10px -20px !important;\n padding-right: 22px;\n padding-bottom: 18px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n \n /* FONT SIZE & SPACING SETTINGS */\n --card-primary-font-size: 1.4rem !important;\n \n /* Increases vertical space between primary and secondary */\n --card-primary-line-height: 1.3 !important;\n}\n" } } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mini-graph-card", "entities": [ "sensor.xiaomi_cn_blt_3_1ni9qhv584c03_mini_temperature_p_2_1001" ], "hours_to_show": 24, "line_width": 5, "show": { "name": false, "icon": false, "state": false, "labels": false, "legend": false }, "color_thresholds": [ { "value": 0, "color": "blue" }, { "value": 16, "color": "lightblue" }, { "value": 18, "color": "orange" }, { "value": 21, "color": "red" } ], "card_mod": { "style": "ha-card {\n background: none;\n box-shadow: none;\n opacity: 50%;\n border: none;\n width: 250px;\n mask-image: radial-gradient(\n ellipse at center,\n rgba(0,0,0,1) 0%,\n rgba(0,0,0,0) 90%\n );\n}\n" } } ], "card_mod": { "style": { ".": "ha-card {\n background: none;\n box-shadow: none;\n border: none;\n margin: 8px 12px; \n position: absolute;\n bottom: -10px;\n right: -10px;\n }\n" } } } ] }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "sensor.xiaomi_cn_blt_3_1ni9qhv584c03_mini_relative_humidity_p_2_1002", "tap_action": { "action": "more-info" }, "icon": "mdi:water-percent", "name": "湿度", "primary_info": "state", "secondary_info": "name", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== CONFIG ========== #}\n {# == Updated: entity auto generated == #}\n {% set hum = states(config.entity) | float(0) %}\n\n {# DEFAULTS #}\n {% set rgb = '120,210,255' %}\n {% set anim = 'hum-good-breathe' %}\n {% set glow_anim = 'hum-good-glow' %}\n {% set halo_anim = 'hum-good-halo' %}\n {% set duration = 3.2 %}\n\n {# RANGES\n < 40 -> BAD (dark blue)\n 40-60 -> GOOD (light blue)\n > 60 -> MIDDLE / humid (medium blue)\n #}\n\n {% if hum < 40 %}\n {# BAD - dry - dark blue #}\n {% set rgb = '0,80,200' %}\n {% set anim = 'hum-bad-pulse' %}\n {% set glow_anim = 'hum-bad-glow' %}\n {% set halo_anim = 'hum-bad-halo' %}\n {% set duration = 2.8 %}\n {% elif hum <= 60 %}\n {# GOOD - light blue #}\n {% set rgb = '120,210,255' %}\n {% set anim = 'hum-good-breathe' %}\n {% set glow_anim = 'hum-good-glow' %}\n {% set halo_anim = 'hum-good-halo' %}\n {% set duration = 3.4 %}\n {% else %}\n {# MIDDLE / humid - medium blue #}\n {% set rgb = '40,140,255' %}\n {% set anim = 'hum-mid-wave' %}\n {% set glow_anim = 'hum-mid-glow' %}\n {% set halo_anim = 'hum-mid-halo' %}\n {% set duration = 3.0 %}\n {% endif %}\n\n --hum-rgb: {{ rgb }};\n --shape-animation: {{ anim }} {{ duration }}s ease-in-out infinite;\n --hum-glow-animation: {{ glow_anim }} {{ (duration * 0.9) | round(2) }}s ease-in-out infinite;\n --hum-halo-animation: {{ halo_anim }} {{ (duration * 1.1) | round(2) }}s ease-in-out infinite;\n\n /* Icon color follows humidity color */\n --icon-color: rgba({{ rgb }}, 1);\n\n /* Neutral pill so theme blue does not leak through */\n background-color: rgba(77,77,77,0.2) !important;\n box-shadow: none !important;\n border: 1px solid rgba(255,255,255,0.06);\n\n opacity: 1;\n position: relative;\n transform-origin: 50% 60%;\n animation: var(--shape-animation);\n}\n\n/* Glow layers */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n inset: -8px;\n animation: var(--hum-glow-animation);\n}\n\n.shape::after {\n inset: -22px;\n animation: var(--hum-halo-animation);\n mix-blend-mode: screen;\n}\n\n/* ========== GOOD - light blue ========== */\n@keyframes hum-good-breathe {\n 0% { transform: scale(0.98); }\n 50% { transform: scale(1.04); }\n 100% { transform: scale(0.98); }\n}\n\n@keyframes hum-good-glow {\n 0% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.55),\n 0 0 30px 4 rgba(var(--hum-rgb), 0.6);\n }\n 50% {\n box-shadow:\n 0 0 24px 4 rgba(var(--hum-rgb), 0.9),\n 0 0 44px 10px rgba(var(--hum-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.55),\n 0 0 30px 4 rgba(var(--hum-rgb), 0.6);\n }\n}\n\n@keyframes hum-good-halo {\n 0% {\n box-shadow:\n 0 0 80px 24px rgba(var(--hum-rgb), 0.35),\n 0 18px 70px -12px rgba(180,230,255,0.3);\n }\n 50% {\n box-shadow:\n 0 0 120px 40px rgba(var(--hum-rgb), 0.45),\n 0 26px 90px -10px rgba(200,240,255,0.45);\n }\n 100% {\n box-shadow:\n 0 0 80px 24px rgba(var(--hum-rgb), 0.35),\n 0 18px 70px -12px rgba(180,230,255,0.3);\n }\n}\n\n/* ========== MIDDLE / humid - medium blue ========== */\n@keyframes hum-mid-wave {\n 0% { transform: translateX(0); }\n 25% { transform: translateX(-1px); }\n 50% { transform: translateX(1px) translateY(-1px); }\n 75% { transform: translateX(-1px); }\n 100% { transform: translateX(0); }\n}\n\n@keyframes hum-mid-glow {\n 0% {\n box-shadow:\n 0 0 20px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 32px 4 rgba(var(--hum-rgb), 0.7);\n }\n 50% {\n box-shadow:\n 0 0 28px 3 rgba(var(--hum-rgb), 0.95),\n 0 0 48px 10px rgba(var(--hum-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 20px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 32px 4 rgba(var(--hum-rgb), 0.7);\n }\n}\n\n@keyframes hum-mid-halo {\n 0% {\n box-shadow:\n 0 0 90px 26px rgba(var(--hum-rgb), 0.4),\n 0 18px 80px -12px rgba(80,190,255,0.35);\n }\n 50% {\n box-shadow:\n 0 0 135px 42px rgba(var(--hum-rgb), 0.5),\n 0 28px 105px -10px rgba(100,210,255,0.5);\n }\n 100% {\n box-shadow:\n 0 0 90px 26px rgba(var(--hum-rgb), 0.4),\n 0 18px 80px -12px rgba(80,190,255,0.35);\n }\n}\n\n/* ========== BAD - dry - dark blue ========== */\n@keyframes hum-bad-pulse {\n 0% { transform: scale(0.97); }\n 40% { transform: scale(1.03); }\n 100% { transform: scale(0.97); }\n}\n\n@keyframes hum-bad-glow {\n 0% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 28px 4 rgba(var(--hum-rgb), 0.7);\n }\n 50% {\n box-shadow:\n 0 0 26px 4 rgba(var(--hum-rgb), 0.95),\n 0 0 44px 12px rgba(var(--hum-rgb), 0.9);\n }\n 100% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 28px 4 rgba(var(--hum-rgb), 0.7);\n }\n}\n\n@keyframes hum-bad-halo {\n 0% {\n box-shadow:\n 0 0 80px 22px rgba(var(--hum-rgb), 0.45),\n 0 18px 75px -10px rgba(0,70,160,0.5);\n }\n 50% {\n box-shadow:\n 0 0 130px 40px rgba(var(--hum-rgb), 0.6),\n 0 26px 100px -8px rgba(0,90,190,0.65);\n }\n 100% {\n box-shadow:\n 0 0 80px 22px rgba(var(--hum-rgb), 0.45),\n 0 18px 75px -10px rgba(0,70,160,0.5);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 48px;\n --icon-color: rgba(var(--hum-rgb),1) !important;\n display: flex;\n margin: -16px 0 10px -20px !important;\n padding-right: 22px;\n padding-bottom: 18px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n \n /* FONT SIZE & SPACING SETTINGS */\n --card-primary-font-size: 1.4rem !important;\n \n /* Increases vertical space between primary and secondary */\n --card-primary-line-height: 1.3 !important;\n}\n" } } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mini-graph-card", "entities": [ "sensor.xiaomi_cn_blt_3_1ni9qhv584c03_mini_relative_humidity_p_2_1002" ], "line_color": "lightblue", "line_width": 5, "hours_to_show": 24, "show": { "name": false, "icon": false, "state": false, "labels": false, "legend": false }, "card_mod": { "style": "ha-card {\n background: none;\n box-shadow: none;\n opacity: 50%;\n border: none;\n width: 250px;\n mask-image: radial-gradient(\n ellipse at center,\n rgba(0,0,0,1) 0%,\n rgba(0,0,0,0) 90%\n );\n}\n" } } ], "card_mod": { "style": { ".": "ha-card {\n background: none;\n box-shadow: none;\n border: none;\n margin: 8px 12px; \n position: absolute;\n bottom: -10px;\n right: -10px;\n }\n" } } } ] } ], "columns": 2 }, { "type": "vertical-stack", "cards": [ { "type": "custom:bubble-card", "card_type": "separator", "icon": "", "card_layout": "large", "rows": "0.5" } ] }, { "type": "custom:mushroom-entity-card", "entity": "binary_sensor.lumi_cn_775597154_acn001_contact_state_p_2_1", "tap_action": { "action": "more-info" }, "icon": "mdi:door", "name": "机柜门", "icon_color": "red", "primary_info": "state", "secondary_info": "name", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {% set is_open = is_state(config.entity, 'on') %}\n\n /* LOGIC: Define colors and animations based on state */\n {% if is_open %}\n /* OPEN: Red, Dark Red Shape, Animated */\n --icon-color-set: rgb(244, 67, 54);\n --shape-color-set: rgba(160, 0, 0, 0.15); \n --shape-animation: door-soft-open 1.7s ease-in-out infinite;\n /* Increased duration slightly for smoother persistent glow */\n --glow-animation: door-soft-glow 2.5s ease-in-out infinite;\n --beam-animation: door-soft-beam 2.5s ease-in-out infinite;\n --icon-filter: drop-shadow(0 0 6px rgba(160, 0, 0, 0.95));\n {% else %}\n /* CLOSED: Green, Dark Green Shape, Static */\n --icon-color-set: rgb(76, 175, 80);\n --shape-color-set: rgba(0, 80, 0, 0.4);\n --shape-animation: none;\n --glow-animation: none;\n --beam-animation: none;\n --icon-filter: none;\n {% endif %}\n\n /* Apply the variable colors defined above */\n background-color: var(--shape-color-set) !important;\n \n /* Standard positioning */\n position: relative;\n transform-origin: 25% 50%;\n animation: var(--shape-animation);\n}\n\n/* Color and Filter for the Icon itself */\n.shape ha-icon {\n color: var(--icon-color-set) !important;\n filter: var(--icon-filter);\n}\n\n/* --- ANIMATION LAYERS --- */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n}\n\n/* Inner Glow */\n.shape::before {\n inset: -10px;\n animation: var(--glow-animation);\n}\n\n/* Outer Beam */\n.shape::after {\n inset: -15px;\n animation: var(--beam-animation);\n mix-blend-mode: screen;\n}\n\n/* --- KEYFRAMES --- */\n@keyframes door-soft-open {\n 0% { transform: rotate(0deg); }\n 40% { transform: rotate(-9deg); }\n 70% { transform: rotate(-6deg); }\n 100% { transform: rotate(0deg); }\n}\n\n@keyframes door-soft-glow {\n 0% {\n box-shadow:\n 0 0 20px 0 rgba(160, 0, 0, 0.7),\n 0 0 40px 6 rgba(160, 0, 0, 0.6),\n 0 0 80px 14px rgba(160, 0, 0, 0.4);\n }\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(200, 0, 0, 1),\n 0 0 70px 16px rgba(200, 0, 0, 0.95),\n 0 0 120px 28px rgba(200, 0, 0, 0.7);\n }\n 100% {\n box-shadow:\n 0 0 20px 0 rgba(160, 0, 0, 0.7),\n 0 0 40px 6 rgba(160, 0, 0, 0.6),\n 0 0 80px 14px rgba(160, 0, 0, 0.4);\n }\n}\n\n/* UPDATED: Huge halo now never fully disappears */\n@keyframes door-soft-beam {\n 0% {\n /* Small, persistent base glow */\n box-shadow:\n 0 0 40px 10px rgba(160, 0, 0, 0.3),\n 0 0 60px 20px rgba(100, 0, 0, 0.2);\n opacity: 0.4; \n }\n 50% {\n /* Maximum Intense Glow */\n box-shadow:\n 0 0 160px 60px rgba(230, 20, 20, 0.8),\n 0 0 230px 100px rgba(160, 0, 0, 0.7);\n opacity: 1;\n }\n 100% {\n /* Return to base glow */\n box-shadow:\n 0 0 40px 10px rgba(160, 0, 0, 0.3),\n 0 0 60px 20px rgba(100, 0, 0, 0.2);\n opacity: 0.4;\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 48px;\n display: flex;\n margin: -5px 0 10px -14px !important;\n padding-right: 22px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n}\n" } }, "grid_options": { "columns": 12, "rows": 1 } }, { "type": "vertical-stack", "cards": [ { "type": "custom:bubble-card", "card_type": "separator", "icon": "", "card_layout": "large", "rows": "0.5" } ] }, { "type": "custom:mushroom-light-card", "entity": "light.lemesh_cn_2077009002_wy0d02_s_2_light", "use_light_color": true, "show_color_temp_control": true, "show_brightness_control": true, "collapsible_controls": false, "show_color_control": true, "name": "机柜灯", "icon_color": "auto", "grid_options": { "columns": 12, "rows": 2 }, "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {% set state_entity = 'light.lemesh_cn_2077009002_wy0d02_s_2_light' %}\n {% set active_value = 'on' %}\n\n {# ======== TRIGGER ======== #}\n {% set trigger_active = (states(state_entity) == active_value) %}\n\n {# ======== COLOR FROM ENTITY (rgb_color) ======== #}\n {% set rgb = state_attr(config.entity, 'rgb_color') %}\n {% if rgb is not none %}\n {% set r = (rgb[0] | int) %}\n {% set g = (rgb[1] | int) %}\n {% set b = (rgb[2] | int) %}\n {% else %}\n {# fallback for CT-only lights #}\n {% set r = 255 %}\n {% set g = 240 %}\n {% set b = 200 %}\n {% endif %}\n\n {% if trigger_active %}\n --shape-animation: lamp-sweep 1.8s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n opacity: 0.5;\n {% endif %}\n\n position: relative;\n transform-origin: 50% 60%;\n}\n\n@keyframes lamp-sweep {\n 0% {\n filter: brightness(1.1);\n box-shadow:\n 0 0 12px 4px rgba({{ r }}, {{ g }}, {{ b }}, 0.9),\n 0 30px 40px -10px rgba({{ r }}, {{ g }}, {{ b }}, 0.0);\n transform: rotate(-4deg) scale(1);\n }\n 25% {\n filter: brightness(1.4);\n box-shadow:\n 0 0 18px 8px rgba({{ r }}, {{ g }}, {{ b }}, 1),\n -8px 35px 45px -12px rgba({{ r }}, {{ g }}, {{ b }}, 0.5);\n transform: rotate(3deg) scale(1.02);\n }\n 50% {\n filter: brightness(1.2);\n box-shadow:\n 0 0 24px 10px rgba({{ r }}, {{ g }}, {{ b }}, 0.9),\n 8px 35px 45px -12px rgba({{ r }}, {{ g }}, {{ b }}, 0.5);\n transform: rotate(-2deg) scale(1.03);\n }\n 75% {\n filter: brightness(1.5);\n box-shadow:\n 0 0 18px 8px rgba({{ r }}, {{ g }}, {{ b }}, 1),\n -6px 30px 40px -12px rgba({{ r }}, {{ g }}, {{ b }}, 0.4);\n transform: rotate(2deg) scale(1.01);\n }\n 100% {\n filter: brightness(1.1);\n box-shadow:\n 0 0 12px 4px rgba({{ r }}, {{ g }}, {{ b }}, 0.8),\n 0 30px 40px -10px rgba({{ r }}, {{ g }}, {{ b }}, 0.0);\n transform: rotate(-4deg) scale(1);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0px 0px -18px !important;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } }, "icon": "mdi:led-strip-variant" }, { "type": "vertical-stack", "cards": [ { "type": "custom:bubble-card", "card_type": "separator", "icon": "", "card_layout": "large", "rows": "0.5" } ] }, { "type": "custom:mushroom-entity-card", "entity": "switch.cuco_cn_2006579195_v3_on_p_2_1", "tap_action": { "action": "none" }, "icon": "mdi:power-socket-au", "icon_color": "light-blue", "name": "Nas 插座", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'switch.cuco_cn_2006579195_v3_on_p_2_1' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# ======== TRIGGER DECISION LOGIC ======== #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set trigger_active = (states(state_entity) == active_value) %}\n {% endif %}\n {# =========== END TRIGGER LOGIC =========== #}\n\n {% if trigger_active %}\n {# adjust speed based on this plug's own power attribute #}\n {% set p = state_attr(config.entity, 'current_power_w') | float(0) %}\n {% set dur = 1.6 - (p / 800) %}\n --shape-animation: ultra-plug-on {{ [0.4, dur] | max | round(2) }}s ease-in-out infinite;\n --plug-glow-animation: ultra-plug-glow 1.8s ease-in-out infinite;\n --plug-arcs-animation: ultra-plug-arcs 1.2s linear infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --plug-glow-animation: none;\n --plug-arcs-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: -4px;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--plug-glow-animation);\n}\n\n.shape::after {\n animation: var(--plug-arcs-animation);\n}\n\n@keyframes ultra-plug-on {\n 0% { transform: scale(1); }\n 25% { transform: scale(1.05) translateY(-1px); }\n 50% { transform: scale(1.08) translateY(-2px); }\n 75% { transform: scale(1.04) translateY(-1px); }\n 100% { transform: scale(1); }\n}\n\n@keyframes ultra-plug-glow {\n 0% {\n box-shadow:\n 0 0 10px 3px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n 0 0 20px 8px rgba(var(--rgb-{{ config.icon_color }}), 0.3);\n }\n 50% {\n box-shadow:\n 0 0 18px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.9),\n 0 0 32px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 0 0 10px 3px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n 0 0 20px 8px rgba(var(--rgb-{{ config.icon_color }}), 0.3);\n }\n}\n\n@keyframes ultra-plug-arcs {\n 0% {\n box-shadow:\n -10px -6px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 12px 4px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n 25% {\n box-shadow:\n -10px -6px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 12px 4px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 50% {\n box-shadow:\n -6px 2px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.3),\n 10px -8px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.7);\n }\n 75% {\n box-shadow:\n -12px 4px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.5),\n 8px 0 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.2);\n }\n 100% {\n box-shadow:\n -10px -6px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 12px 4px 0 -4px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } }, "grid_options": { "columns": 12, "rows": 1.5 } }, { "type": "custom:mushroom-entity-card", "entity": "sensor.cuco_cn_2006579195_v3_electric_power_p_11_2", "icon": "mdi:nas", "icon_color": "red", "hold_action": { "action": "more-info" }, "double_tap_action": { "action": "none" }, "name": "Nas Plug", "card_mod": { "style": { ".": "ha-card {\n /* ================= USER SETTINGS ================= */\n {% set power_entity = 'sensor.cuco_cn_2006579195_v3_electric_power_p_11_2' %}\n {% set max_w = 60 %} \n /* ================================================= */\n\n /* --- LOGIC --- */\n {% set current_w = states(power_entity) | float(0) %}\n \n /* ACTIVE determines if animations/glows are ON (depends only on power) */\n {% set active = current_w > 0 %}\n \n /* Calculate Load Percentage */\n {% set width_pct = (current_w / max_w * 100) | round(2) %}\n {% if width_pct > 100 %}{% set width_pct = 100 %}{% endif %}\n \n /* --- PASS VARIABLES TO CSS --- */\n /* Define the color we want the effects to use (from config) */\n --active-color: var(--rgb-{{ config.icon_color }});\n \n --bar-width: {{ width_pct }}%;\n --bar-opacity: {{ 1 if active else 0 }};\n \n /* Text color: If power > 0, show colored text. Else dim. */\n --text-color: {{ 'rgba(var(--active-color), 1)' if active else 'rgba(255,255,255,0.5)' }};\n \n /* PASS ANIMATION VARIABLES DOWN TO SHADOW DOM */\n --shape-animation: {{ 'ultra-plug-on 3s ease-in-out infinite' if active else 'none' }};\n --plug-glow-animation: {{ 'ultra-plug-glow 3s ease-in-out infinite' if active else 'none' }};\n --plug-arcs-animation: {{ 'ultra-plug-arcs 3s linear infinite' if active else 'none' }};\n --effect-opacity: {{ 1 if active else 0 }};\n \n /* --- CARD STYLING --- */\n {% if active %}\n background-color: #1c1c1c !important;\n border: none !important;\n background-image: \n radial-gradient(circle at 24px 24px, rgba(var(--active-color), 0.35) 0%, rgba(var(--active-color), 0.1) 40%, transparent 80%),\n linear-gradient(to right, rgba(255,255,255,0.1), rgba(255,255,255,0.1)) !important;\n background-size: 100% 100%, 100% 6px !important;\n background-position: top left, bottom left !important;\n background-repeat: no-repeat !important;\n {% else %}\n /* When Power is 0: Clean slate */\n background-image: none !important;\n box-shadow: none !important;\n {% endif %}\n\n border-radius: 12px;\n position: relative;\n overflow: hidden;\n transition: all 0.5s ease;\n}\n\n/* --- WATTAGE BADGE (Top Right) --- */\nha-card::before {\n content: '{{ current_w | round(1) }} W';\n position: absolute;\n top: 12px;\n right: 12px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.5px;\n color: var(--text-color);\n \n /* Only show badge background if active */\n background: {{ 'rgba(0, 0, 0, 0.2)' if active else 'transparent' }};\n border: {{ '1px solid rgba(255, 255, 255, 0.1)' if active else 'none' }};\n \n padding: 4px 8px;\n border-radius: 6px;\n backdrop-filter: blur(2px);\n transition: all 0.5s ease;\n z-index: 2;\n}\n\n/* --- ACTIVE PROGRESS BAR (BEAM) --- */\nha-card::after {\n content: '';\n position: absolute;\n bottom: 0; left: 0;\n height: 6px;\n width: var(--bar-width);\n \n background: linear-gradient(90deg, \n rgba(var(--active-color), 0.4) 0%, \n rgba(var(--active-color), 1) 100%\n );\n \n box-shadow: 0 -2px 15px rgba(var(--active-color), 0.9);\n opacity: var(--bar-opacity);\n transition: width 0.5s ease-out, opacity 0.5s ease;\n animation: current-flow 1.5s infinite linear;\n}\n\n@keyframes current-flow {\n 0% { filter: brightness(1); opacity: 0.8; }\n 50% { filter: brightness(1.5); opacity: 1; }\n 100% { filter: brightness(1); opacity: 0.8; }\n}\n\nmushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 15px;\n padding-bottom: 15px;\n}\n", "mushroom-shape-icon$": ".shape {\n /* Receive animation variables from Main Card logic */\n animation: var(--shape-animation) !important;\n overflow: visible !important;\n position: relative;\n}\n\n/* Create the Pseudo-Elements for Glow and Arcs */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: -4px;\n border-radius: inherit;\n pointer-events: none;\n opacity: var(--effect-opacity); \n}\n\n/* Glow Layer */\n.shape::before {\n animation: var(--plug-glow-animation);\n}\n\n/* Electric Arcs Layer */\n.shape::after {\n animation: var(--plug-arcs-animation);\n}\n\n/* --- ANIMATION KEYFRAMES --- */\n/* Note: We use var(--active-color) so the glow stays green even if icon is gray */\n\n@keyframes ultra-plug-on {\n 0% { transform: scale(1); }\n 25% { transform: scale(1.05) translateY(-1px); }\n 50% { transform: scale(1.08) translateY(-2px); }\n 75% { transform: scale(1.04) translateY(-1px); }\n 100% { transform: scale(1); }\n}\n\n@keyframes ultra-plug-glow {\n 0% {\n box-shadow:\n 0 0 10px 3px rgba(var(--active-color), 0.6),\n 0 0 20px 8px rgba(var(--active-color), 0.3);\n }\n 50% {\n box-shadow:\n 0 0 18px 6px rgba(var(--active-color), 0.9),\n 0 0 32px 12px rgba(var(--active-color), 0.4);\n }\n 100% {\n box-shadow:\n 0 0 10px 3px rgba(var(--active-color), 0.6),\n 0 0 20px 8px rgba(var(--active-color), 0.3);\n }\n}\n\n@keyframes ultra-plug-arcs {\n 0% {\n box-shadow:\n -10px -6px 0 -4px rgba(var(--active-color), 0.0),\n 12px 4px 0 -4px rgba(var(--active-color), 0.0);\n }\n 25% {\n box-shadow:\n -10px -6px 0 -4px rgba(var(--active-color), 0.7),\n 12px 4px 0 -4px rgba(var(--active-color), 0.4);\n }\n 50% {\n box-shadow:\n -6px 2px 0 -4px rgba(var(--active-color), 0.3),\n 10px -8px 0 -4px rgba(var(--active-color), 0.7);\n }\n 75% {\n box-shadow:\n -12px 4px 0 -4px rgba(var(--active-color), 0.5),\n 8px 0 0 -4px rgba(var(--active-color), 0.2);\n }\n 100% {\n box-shadow:\n -10px -6px 0 -4px rgba(var(--active-color), 0.0),\n 12px 4px 0 -4px rgba(var(--active-color), 0.0);\n }\n}\n" } }, "grid_options": { "columns": 12, "rows": 1.5 } }, { "type": "custom:mushroom-entity-card", "entity": "sensor.cuco_cn_2006579195_v3_power_consumption_p_11_1", "tap_action": { "action": "more-info" }, "name": "用电量", "icon": "mdi:lightning-bolt", "primary_info": "state", "secondary_info": "name", "icon_color": "light-grey", "card_mod": { "style": "ha-card {\n /* ===== LOGIC & SETTINGS ===== */\n {% set state = states(config.entity) %}\n /* 1. Get the Grass Sensor Data */\n {% set grass = states('sensor.cuco_cn_2006579195_v3_power_consumption_p_11_1') %}\n \n /* 2. Define Colors based on state */\n {% if state in ['high', 'very-high', 'red'] %}\n {% set c1 = '255, 65, 108' %} /* Red RGB */\n {% set c2 = '255, 75, 43' %} /* Orange RGB */\n {% set speed = '4s' %}\n {% elif state in ['moderate', 'medium', 'orange'] %}\n {% set c1 = '247, 151, 30' %} /* Orange RGB */\n {% set c2 = '255, 210, 0' %} /* Yellow RGB */\n {% set speed = '7s' %}\n {% else %}\n {% set c1 = '0, 242, 96' %} /* Green RGB */\n {% set c2 = '5, 117, 230' %} /* Blue RGB */\n {% set speed = '12s' %}\n {% endif %}\n\n /* 3. Pass variables to CSS */\n --aura-color-1: rgba({{ c1 }}, 0.6);\n --aura-color-2: rgba({{ c2 }}, 0.6);\n --speed: {{ speed }};\n \n /* 4. Card Body Styling */\n background: #101010 !important;\n border-radius: 25px;\n border: 1px solid rgba(255,255,255,0.08);\n position: relative;\n overflow: hidden;\n box-shadow: inset 0 0 20px rgba(0,0,0,0.5);\n}\n\nha-card::before {\n content: \"\";\n position: absolute;\n top: -50%; left: -50%;\n width: 200%; height: 200%;\n z-index: 0;\n \n /* Two radial gradients in one element */\n background-image: \n radial-gradient(circle at 50% 50%, var(--aura-color-1) 0%, transparent 50%),\n radial-gradient(circle at 80% 80%, var(--aura-color-2) 0%, transparent 50%);\n \n filter: blur(60px);\n opacity: 0.8;\n animation: rotate-aura var(--speed) linear infinite;\n}\n\nha-card::after {\n /* INJECT THE DATA HERE */\n content: '{{ grass }}';\n \n position: absolute;\n top: 50%; \n right: 16px;\n transform: translateY(-50%);\n z-index: 10;\n \n /* Badge Styling (Like the battery example) */\n color: white;\n font-weight: 700;\n font-size: 14px;\n background: rgba(0, 0, 0, 0.4);\n border: 1px solid rgba(255, 255, 255, 0.15);\n backdrop-filter: blur(4px);\n padding: 4px 10px;\n border-radius: 12px;\n text-shadow: 0 1px 2px black;\n}\n\n/* --- GLASS SURFACE OVERLAY --- */\nmushroom-shape-icon {\n --icon-size: 68px;\n --icon-color: rgba(var(--voc-rgb),1) !important;\n display: flex;\n margin: -18px 0 10px -15px !important;\n padding-right: 22px;\n padding-bottom: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n\n --card-primary-font-size: 1.2rem !important;\n --card-primary-line-height: 1.3 !important;\n}\n\n/* Typography */\n.mushroom-state-info span.primary {\n color: white !important;\n font-weight: 600 !important;\n font-size: 16px !important;\n text-shadow: 0 2px 4px rgba(0,0,0,0.5);\n}\n.mushroom-state-info span.secondary {\n color: rgba(255,255,255,0.8) !important;\n}\n\n/* Icon Styling */\nmushroom-shape-icon {\n --icon-size: 60px;\n --icon-color: white !important;\n}\nha-state-icon {\n color: white !important;\n}\n\n/* Animation */\n@keyframes rotate-aura {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n" }, "grid_options": { "columns": 12, "rows": 1.5 } } ], "column_span": 1 } ], "cards": [], "visible": [ { "user": "7a6c93d08acc4692bfd561154bb386df" }, { "user": "7809f2c31fda449b8e7c5a0d2eaf5fd5" } ] }, { "type": "masonry", "path": "wash", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "sensor.875060396221041554_bsh_common_setting_powerstate", "name": "洗衣机", "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 {\n /* ======================== */\n /* USER CONFIGURATION */\n /* ======================== */\n \n /* 1. ENTITIES (Update these!) */\n {% set ent_status = 'sensor.bshcn_cn_x_13164_37533621_875060396221041554_e0ec0342_k7d00w_status_p_2_24' %}\n {% set ent_timerem = 'sensor.bshcn_cn_x_13164_37533621_875060396221041554_e0ec0342_k7d00w_left_time_p_2_1' %}\n {% set max_time = 120 %}\n {% set ent_power = 'sensor.smart_plug_power' %}\n\n /* OPTIONAL Progress Percentage Sensor (if exists) */\n {% set ent_percent = 'sensor.875060396221041554_bsh_common_option_programprogress' %}\n\n /* 2. SIZES (Px) */\n --config-icon-size: 65px;\n --config-font-primary: 15px;\n --config-font-secondary: 12px;\n --config-font-badge: 12px;\n /* ======================== */\n\n /* --- SENSORS & TIME --- */\n {% set status = states(ent_status) %}\n {% set status_clean = status | replace('-', ' ') | title %}\n {% set time_rem = states(ent_timerem) | int(0) %}\n {% set raw_percent = states(ent_percent) | float(-1) %}\n\n /* --- POWER CALCULATION --- */\n {% set power_w = states(ent_power) | float(0) | round %}\n {% set power_text = ' • ' ~ power_w ~ 'W' if power_w > 0 else '' %}\n \n /* Format Time (min -> Xh Ym) */\n {% set hours = (time_rem / 60) | int %}\n {% set mins = time_rem % 60 %}\n {% set time_formatted = '%dh %02dm' | format(hours, mins) %}\n\n /* --- PROGRESS CALCULATION --- */\n \n {% if status | lower in ['idle', 'off', 'standby', 'unknown', 'unavailable'] %}\n {% set progress = 0 %}\n {% set badge_text = status_clean ~ power_text %}\n {% else %}\n \n /* LOGIC: Use Sensor if available, otherwise Calculate */\n {% if raw_percent >= 0 %}\n /* Use the sensor provided percentage */\n {% set progress = raw_percent | int %}\n {% else %}\n /* Fallback: Calculate based on max_time */\n {% set max_cycle_time = max_time %}\n {% set calc_prog = ((max_cycle_time - time_rem) / max_cycle_time * 100) | int %}\n {% set progress = [5, [calc_prog, 100] | min] | max %}\n {% endif %}\n\n {% set badge_text = status_clean ~ ' • ' ~ time_formatted ~ power_text %}\n {% endif %}\n\n /* --- STATE DEFINITIONS --- */\n {% set s_lower = status | lower %}\n {% set is_running = s_lower in ['wash', 'washing', 'rinse', 'rinsing', 'pre-wash', 'soak'] %}\n {% set is_spinning = s_lower in ['spin', 'spinning'] %}\n {% set is_drying = s_lower in ['dry', 'drying'] %}\n {% set is_done = s_lower in ['finished', 'complete', 'end'] %}\n\n /* --- ASSIGN ANIMATIONS --- */\n {% if is_drying %}\n {% set color = '255, 152, 0' %} /* Orange */\n {% set anim_type = 'steam-rise 2s ease-in-out infinite' %}\n {% set icon_shake = 'none' %}\n {% set wave_anim = 'wave 4s linear infinite' %}\n {% set overlay_img = 'linear-gradient(0deg, transparent, rgba(255,255,255,0.5), transparent)' %}\n \n {% elif is_spinning %}\n {% set color = '0, 255, 255' %} /* cyan */\n {% set anim_type = 'none' %}\n {% set icon_shake = 'washer-spin-smooth 0.8s linear infinite' %}\n {% set wave_anim = 'wave 2s linear infinite' %} /* Fast Wave */\n {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.3) 10%, transparent 60%)' %}\n\n {% elif is_done %}\n {% set color = '76, 175, 80' %} /* Green */\n {% set anim_type = 'sparkle 2s infinite' %}\n {% set icon_shake = 'none' %}\n {% set wave_anim = 'wave 4s linear infinite' %}\n {% set overlay_img = 'radial-gradient(circle, rgba(255,255,255,0.8) 10%, transparent 60%)' %}\n\n {% elif is_running %}\n {% set color = '33, 150, 243' %} /* Blue */\n {% set anim_type = 'bubbles 1s linear infinite' %}\n {% set icon_shake = 'shake 1.5s ease-in-out infinite' %} /* Slow Shake */\n {% set wave_anim = 'wave 4s linear infinite' %}\n {% set overlay_img = 'radial-gradient(2px 2px at 20% 80%, white, transparent), radial-gradient(2px 2px at 50% 70%, white, transparent)' %}\n \n {% else %}\n {% set color = '158, 158, 158' %} /* Grey */\n {% set anim_type = 'none' %}\n {% set icon_shake = 'none' %}\n {% set wave_anim = 'none' %}\n {% set overlay_img = 'none' %}\n {% endif %}\n\n /* --- OUTPUT VARIABLES --- */\n --wm-color: {{ color }};\n --wm-level: {{ progress }}%;\n --wm-anim-overlay: {{ anim_type }};\n --wm-anim-shake: {{ icon_shake }};\n --wm-anim-wave: {{ wave_anim }};\n --wm-overlay-bg: {{ overlay_img }};\n --wm-badge-content: \"{{ badge_text }}\";\n \n transition: all 0.5s ease;\n overflow: hidden;\n}\n\n/* BADGE */\nha-card::before {\n content: var(--wm-badge-content);\n position: absolute;\n top: 10px; right: 10px;\n background: rgba(var(--wm-color), 0.15);\n color: rgb(var(--wm-color));\n border: 1px solid rgba(var(--wm-color), 0.3);\n padding: 2px 10px;\n border-radius: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n font-size: var(--config-font-badge);\n}\n\n/* BAR */\nha-card::after {\n content: '';\n position: absolute;\n bottom: 0; left: 0;\n height: 4px;\n width: var(--wm-level);\n background: rgb(var(--wm-color));\n box-shadow: 0 0 10px rgb(var(--wm-color));\n transition: width 0.5s ease;\n}\n", "mushroom-shape-icon$": ".shape {\n --icon-size: var(--config-icon-size) !important;\n background: rgba(255, 255, 255, 0.05) !important;\n overflow: hidden;\n position: relative;\n border: 1px solid rgba(255,255,255,0.1);\n \n /* Apply the animation determined by the Logic below */\n animation: var(--wm-anim-shake) !important;\n transform-origin: center center; \n}\n\n/* Wave Layer */\n.shape::before {\n content: '';\n position: absolute;\n left: -50%;\n width: 200%; height: 200%;\n top: calc(100% - var(--wm-level));\n background: rgba(var(--wm-color), 0.6);\n border-radius: 40%;\n animation: var(--wm-anim-wave);\n}\n\n/* Overlay Layer (Bubbles/Steam) */\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n background-image: var(--wm-overlay-bg);\n background-size: 100% 100%;\n animation: var(--wm-anim-overlay);\n z-index: 2;\n}\n\n/* The Icon Itself */\nha-icon {\n z-index: 3;\n mix-blend-mode: overlay;\n color: white !important;\n}\n\n/* --- KEYFRAMES --- */\n@keyframes wave {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n@keyframes shake {\n 0%, 100% { transform: rotate(0deg); }\n 25% { transform: rotate(5deg) translateY(-1px); }\n 75% { transform: rotate(-5deg) translateY(1px); }\n}\n@keyframes bubbles {\n 0% { transform: translateY(10px); opacity: 0; }\n 50% { opacity: 1; }\n 100% { transform: translateY(-20px); opacity: 0; }\n}\n@keyframes steam-rise {\n 0% { opacity: 0; transform: translateY(5px); }\n 50% { opacity: 0.8; }\n 100% { opacity: 0; transform: translateY(-10px); }\n}\n@keyframes sparkle {\n 0%, 100% { opacity: 0.3; transform: scale(0.9); }\n 50% { opacity: 1; transform: scale(1.1); }\n}\n\n@keyframes washer-spin-smooth {\n 0% {\n transform: rotate(0deg) translate(0,0);\n box-shadow: inset 0 0 0 2px rgba(var(--wm-color), 0.7);\n }\n 25% { transform: rotate(90deg) translate(0.5px, 0.5px); }\n 50% { transform: rotate(180deg) translate(0,0); }\n 75% { transform: rotate(270deg) translate(-0.5px, -0.5px); }\n 100% {\n transform: rotate(360deg) translate(0,0);\n box-shadow: inset 0 0 0 2px rgba(var(--wm-color), 0.7);\n }\n}\n", "mushroom-state-info$": ".container .primary {\n font-size: var(--config-font-primary) !important;\n}\n.container .secondary {\n font-size: var(--config-font-secondary) !important;\n}\n" } }, "grid_options": { "columns": 12, "rows": 1 } } ], "icon": "mdi:washing-machine", "visible": [ { "user": "7a6c93d08acc4692bfd561154bb386df" }, { "user": "7809f2c31fda449b8e7c5a0d2eaf5fd5" } ] }, { "type": "sections", "max_columns": 4, "title": "测试", "path": "unknown", "sections": [ { "type": "grid", "cards": [ { "type": "heading", "heading": "新建部件" }, { "type": "custom:mushroom-entity-card", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "tap_action": { "action": "toggle" }, "icon": "mdi:fan", "icon_color": "cyan", "name": "Fan", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'fan.xiaomi_cn_2196552583_p90_s_2_fan' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# -------- TRIGGER DECISION LOGIC -------- #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set sensor_entity = state_entity %}\n {% if states(sensor_entity) == active_value %}\n {% set trigger_active = true %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% endif %}\n {# ------ END TRIGGER DECISION LOGIC ------ #}\n\n {# Fan speed still based on THIS card's entity percentage #}\n {% set speed = state_attr(config.entity, 'percentage') | int(0) %}\n\n {% if trigger_active %}\n {% if speed == 0 and is_state(config.entity, 'off') %}\n --shape-animation: fan-ultra-idle 3s ease-in-out infinite;\n {% else %}\n {% set dur = 1.2 - (speed / 120) %}\n --shape-animation: fan-ultra-spin {{ [0.25, dur] | max | round(2) }}s linear infinite;\n {% endif %}\n --fan-warp-animation: fan-warp 1.4s ease-in-out infinite;\n --fan-stream-animation: fan-stream 1.6s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --fan-warp-animation: none;\n --fan-stream-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--fan-warp-animation);\n}\n\n.shape::after {\n mix-blend-mode: screen;\n animation: var(--fan-stream-animation);\n}\n\n@keyframes fan-ultra-spin {\n 0% {\n transform: rotate(0deg) scale(1);\n filter: drop-shadow(0 0 3px rgba(var(--rgb-{{ config.icon_color }}), 0.8));\n }\n 20% { transform: rotate(72deg) scale(1.03); }\n 40% { transform: rotate(144deg) scale(1.05); }\n 60% { transform: rotate(216deg) scale(1.03); }\n 80% { transform: rotate(288deg) scale(1.02); }\n 100% {\n transform: rotate(360deg) scale(1);\n filter: drop-shadow(0 0 5px rgba(var(--rgb-{{ config.icon_color }}), 1));\n }\n}\n\n@keyframes fan-ultra-idle {\n 0% { transform: rotate(-6deg); }\n 50% { transform: rotate(6deg); }\n 100% { transform: rotate(-6deg); }\n}\n\n@keyframes fan-warp {\n 0% {\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 40% {\n box-shadow:\n 0 0 0 8px rgba(var(--rgb-{{ config.icon_color }}), 0.4),\n 0 0 24px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 100% {\n box-shadow:\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 40px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes fan-stream {\n 0% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n 50% {\n box-shadow:\n 24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n -24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } } }, { "type": "custom:mushroom-entity-card", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "tap_action": { "action": "toggle" }, "icon": "mdi:fan", "icon_color": "cyan", "name": "Fan", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'fan.shhf_cn_1129134246_sflt11_s_11_fan' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# -------- TRIGGER DECISION LOGIC -------- #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set sensor_entity = state_entity %}\n {% if states(sensor_entity) == active_value %}\n {% set trigger_active = true %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% endif %}\n {# ------ END TRIGGER DECISION LOGIC ------ #}\n\n {# Fan speed still based on THIS card's entity percentage #}\n {% set speed = state_attr(config.entity, 'percentage') | int(0) %}\n\n {% if trigger_active %}\n {% if speed == 0 and is_state(config.entity, 'off') %}\n --shape-animation: fan-ultra-idle 3s ease-in-out infinite;\n {% else %}\n {% set dur = 1.2 - (speed / 120) %}\n --shape-animation: fan-ultra-spin {{ [0.25, dur] | max | round(2) }}s linear infinite;\n {% endif %}\n --fan-warp-animation: fan-warp 1.4s ease-in-out infinite;\n --fan-stream-animation: fan-stream 1.6s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --fan-warp-animation: none;\n --fan-stream-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--fan-warp-animation);\n}\n\n.shape::after {\n mix-blend-mode: screen;\n animation: var(--fan-stream-animation);\n}\n\n@keyframes fan-ultra-spin {\n 0% {\n transform: rotate(0deg) scale(1);\n filter: drop-shadow(0 0 3px rgba(var(--rgb-{{ config.icon_color }}), 0.8));\n }\n 20% { transform: rotate(72deg) scale(1.03); }\n 40% { transform: rotate(144deg) scale(1.05); }\n 60% { transform: rotate(216deg) scale(1.03); }\n 80% { transform: rotate(288deg) scale(1.02); }\n 100% {\n transform: rotate(360deg) scale(1);\n filter: drop-shadow(0 0 5px rgba(var(--rgb-{{ config.icon_color }}), 1));\n }\n}\n\n@keyframes fan-ultra-idle {\n 0% { transform: rotate(-6deg); }\n 50% { transform: rotate(6deg); }\n 100% { transform: rotate(-6deg); }\n}\n\n@keyframes fan-warp {\n 0% {\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 40% {\n box-shadow:\n 0 0 0 8px rgba(var(--rgb-{{ config.icon_color }}), 0.4),\n 0 0 24px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 100% {\n box-shadow:\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 40px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes fan-stream {\n 0% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n 50% {\n box-shadow:\n 24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n -24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "tap_action": { "action": "toggle" }, "icon": "mdi:fan", "icon_color": "cyan", "name": "餐桌扇", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'fan.shhf_cn_1129134246_sflt11_s_11_fan' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# -------- TRIGGER DECISION LOGIC -------- #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set sensor_entity = state_entity %}\n {% if states(sensor_entity) == active_value %}\n {% set trigger_active = true %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% endif %}\n {# ------ END TRIGGER DECISION LOGIC ------ #}\n\n {# Fan speed still based on THIS card's entity percentage #}\n {% set speed = state_attr(config.entity, 'percentage') | int(0) %}\n\n {% if trigger_active %}\n {% if speed == 0 and is_state(config.entity, 'off') %}\n --shape-animation: fan-ultra-idle 3s ease-in-out infinite;\n {% else %}\n {% set dur = 1.2 - (speed / 120) %}\n --shape-animation: fan-ultra-spin {{ [0.25, dur] | max | round(2) }}s linear infinite;\n {% endif %}\n --fan-warp-animation: fan-warp 1.4s ease-in-out infinite;\n --fan-stream-animation: fan-stream 1.6s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --fan-warp-animation: none;\n --fan-stream-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--fan-warp-animation);\n}\n\n.shape::after {\n mix-blend-mode: screen;\n animation: var(--fan-stream-animation);\n}\n\n@keyframes fan-ultra-spin {\n 0% {\n transform: rotate(0deg) scale(1);\n filter: drop-shadow(0 0 3px rgba(var(--rgb-{{ config.icon_color }}), 0.8));\n }\n 20% { transform: rotate(72deg) scale(1.03); }\n 40% { transform: rotate(144deg) scale(1.05); }\n 60% { transform: rotate(216deg) scale(1.03); }\n 80% { transform: rotate(288deg) scale(1.02); }\n 100% {\n transform: rotate(360deg) scale(1);\n filter: drop-shadow(0 0 5px rgba(var(--rgb-{{ config.icon_color }}), 1));\n }\n}\n\n@keyframes fan-ultra-idle {\n 0% { transform: rotate(-6deg); }\n 50% { transform: rotate(6deg); }\n 100% { transform: rotate(-6deg); }\n}\n\n@keyframes fan-warp {\n 0% {\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 40% {\n box-shadow:\n 0 0 0 8px rgba(var(--rgb-{{ config.icon_color }}), 0.4),\n 0 0 24px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 100% {\n box-shadow:\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 40px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes fan-stream {\n 0% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n 50% {\n box-shadow:\n 24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n -24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } } }, { "type": "vertical-stack", "cards": [ { "type": "custom:bubble-card", "card_type": "separator", "icon": "", "card_layout": "large", "rows": "0.5" } ] }, { "type": "custom:mushroom-entity-card", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "tap_action": { "action": "toggle" }, "icon": "mdi:fan", "icon_color": "cyan", "name": "小爱风扇", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'fan.xiaomi_cn_2196552583_p90_s_2_fan' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# -------- TRIGGER DECISION LOGIC -------- #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set sensor_entity = state_entity %}\n {% if states(sensor_entity) == active_value %}\n {% set trigger_active = true %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% endif %}\n {# ------ END TRIGGER DECISION LOGIC ------ #}\n\n {# Fan speed still based on THIS card's entity percentage #}\n {% set speed = state_attr(config.entity, 'percentage') | int(0) %}\n\n {% if trigger_active %}\n {% if speed == 0 and is_state(config.entity, 'off') %}\n --shape-animation: fan-ultra-idle 3s ease-in-out infinite;\n {% else %}\n {% set dur = 1.2 - (speed / 120) %}\n --shape-animation: fan-ultra-spin {{ [0.25, dur] | max | round(2) }}s linear infinite;\n {% endif %}\n --fan-warp-animation: fan-warp 1.4s ease-in-out infinite;\n --fan-stream-animation: fan-stream 1.6s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --fan-warp-animation: none;\n --fan-stream-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--fan-warp-animation);\n}\n\n.shape::after {\n mix-blend-mode: screen;\n animation: var(--fan-stream-animation);\n}\n\n@keyframes fan-ultra-spin {\n 0% {\n transform: rotate(0deg) scale(1);\n filter: drop-shadow(0 0 3px rgba(var(--rgb-{{ config.icon_color }}), 0.8));\n }\n 20% { transform: rotate(72deg) scale(1.03); }\n 40% { transform: rotate(144deg) scale(1.05); }\n 60% { transform: rotate(216deg) scale(1.03); }\n 80% { transform: rotate(288deg) scale(1.02); }\n 100% {\n transform: rotate(360deg) scale(1);\n filter: drop-shadow(0 0 5px rgba(var(--rgb-{{ config.icon_color }}), 1));\n }\n}\n\n@keyframes fan-ultra-idle {\n 0% { transform: rotate(-6deg); }\n 50% { transform: rotate(6deg); }\n 100% { transform: rotate(-6deg); }\n}\n\n@keyframes fan-warp {\n 0% {\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 40% {\n box-shadow:\n 0 0 0 8px rgba(var(--rgb-{{ config.icon_color }}), 0.4),\n 0 0 24px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 100% {\n box-shadow:\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 40px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes fan-stream {\n 0% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n 50% {\n box-shadow:\n 24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n -24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } } } ] } ] } ], "visible": [ { "user": "7a6c93d08acc4692bfd561154bb386df" }, { "user": "7809f2c31fda449b8e7c5a0d2eaf5fd5" } ], "cards": [] }, { "type": "sections", "path": "anashost", "max_columns": 4, "title": "Anashost", "icon": "mdi:test-tube", "sections": [ { "type": "grid", "cards": [ { "type": "heading", "heading": "新建部件" }, { "type": "custom:stack-in-card", "mode": "vertical", "keep": { "outer_padding": false, "margin": true }, "cards": [ { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1", "icon_color": "{{states('sensor.livingroom_temp_color_no_rgb')}}", "icon": "mdi:thermometer", "use_entity_picture": true, "double_tap_action": { "action": "none" }, "hold_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unavailable') %}\n -\n{% elif is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unknown') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1')}}°\n{% endif %}" }, { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2", "icon_color": "light-blue", "icon": "mdi:water-percent", "name": "", "use_entity_picture": true, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2','unavailable') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2')}}%\n{% endif %}" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:lightbulb-group", "content": "{% if is_state('sensor.lights_of_count','0') %}\n \n{% else %}\n {{states('sensor.lights_of_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.lights_of_count')|float %}\n{% if state <= 0 %} grey\n{% else %} amber\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.lights_of_count" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:water", "content": "{% if is_state('sensor.water_damage_count','0') %}\n \n{% else %}\n {{states('sensor.water_damage_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.water_damage_count')|float %}\n{% if state <= 0 %} grey\n{% else %} blue\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.water_damage_count" } ], "alignment": "center" }, { "type": "custom:swipe-card", "mode": "vertical", "keep": { "outer_padding": false, "margin": true, "box_shadow": false, "background": false }, "cards": [ { "type": "horizontal-stack", "cards": [ { "type": "custom:mushroom-entity-card", "card_mod": { "style": "ha-card{\n box-shadow: none;\n }\n" }, "entity": "input_boolean.on_state", "double_tap_action": { "action": "none" }, "icon": "mdi:home", "icon_color": "teal", "layout": "vertical", "hold_action": { "action": "none" }, "tap_action": { "action": "navigate", "navigation_path": "main-home" }, "primary_info": "none", "secondary_info": "name", "name": "首页" }, { "type": "custom:mushroom-entity-card", "card_mod": { "style": "ha-card{\n box-shadow: none;\n }\n" }, "entity": "input_boolean.on_state", "icon": "mdi:server", "icon_color": "white", "layout": "vertical", "primary_info": "none", "secondary_info": "name", "tap_action": { "action": "navigate", "navigation_path": "home-server" }, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "name": "机房" }, { "type": "custom:mushroom-entity-card", "card_mod": { "style": "ha-card{\n box-shadow: none;\n }\n" }, "entity": "light.quan_wu_zhao_ming", "icon_color": "yellow", "secondary_info": "name", "layout": "vertical", "name": "Lights", "double_tap_action": { "action": "none" }, "hold_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "primary_info": "none", "icon": "mdi:lamps" } ] } ] } ] }, { "type": "custom:stack-in-card", "mode": "vertical", "keep": { "outer_padding": false, "margin": true }, "cards": [ { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1", "icon_color": "{{states('sensor.livingroom_temp_color_no_rgb')}}", "icon": "mdi:thermometer", "use_entity_picture": true, "double_tap_action": { "action": "none" }, "hold_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unavailable') %}\n -\n{% elif is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unknown') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1')}}°\n{% endif %}" }, { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2", "icon_color": "light-blue", "icon": "mdi:water-percent", "name": "", "use_entity_picture": true, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2','unavailable') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2')}}%\n{% endif %}" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:lightbulb-group", "content": "{% if is_state('sensor.lights_of_count','0') %}\n \n{% else %}\n {{states('sensor.lights_of_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.lights_of_count')|float %}\n{% if state <= 0 %} grey\n{% else %} amber\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.lights_of_count" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:water", "content": "{% if is_state('sensor.water_damage_count','0') %}\n \n{% else %}\n {{states('sensor.water_damage_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.water_damage_count')|float %}\n{% if state <= 0 %} grey\n{% else %} blue\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.water_damage_count" } ], "alignment": "center" } ] }, { "type": "custom:stack-in-card", "mode": "vertical", "keep": { "outer_padding": false, "margin": true }, "cards": [ { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1", "icon_color": "{{states('sensor.livingroom_temp_color_no_rgb')}}", "icon": "mdi:thermometer", "use_entity_picture": true, "double_tap_action": { "action": "none" }, "hold_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unavailable') %}\n -\n{% elif is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1','unknown') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1')}}°\n{% endif %}" }, { "type": "template", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2", "icon_color": "light-blue", "icon": "mdi:water-percent", "name": "", "use_entity_picture": true, "hold_action": { "action": "none" }, "double_tap_action": { "action": "none" }, "tap_action": { "action": "more-info" }, "content": "{% if is_state('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2','unavailable') %}\n -\n{% else %}\n {{states('sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2')}}%\n{% endif %}" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:lightbulb-group", "content": "{% if is_state('sensor.lights_of_count','0') %}\n \n{% else %}\n {{states('sensor.lights_of_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.lights_of_count')|float %}\n{% if state <= 0 %} grey\n{% else %} amber\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.lights_of_count" }, { "type": "template", "double_tap_action": { "action": "none" }, "icon": "mdi:water", "content": "{% if is_state('sensor.water_damage_count','0') %}\n \n{% else %}\n {{states('sensor.water_damage_count')}}\n{% endif %}", "icon_color": "{% set state = states('sensor.water_damage_count')|float %}\n{% if state <= 0 %} grey\n{% else %} blue\n{% endif %}", "hold_action": { "action": "none" }, "tap_action": { "action": "none" }, "entity": "sensor.water_damage_count" } ], "alignment": "center" } ], "card_mod": { "style": "ha-card {\n background-color: rgba(255, 255, 255, 0) !important;\n box-shadow: none !important;\n padding: 2px 0px 2px 0px;\n}\n" } } ] } ], "visible": [ { "user": "7a6c93d08acc4692bfd561154bb386df" }, { "user": "7809f2c31fda449b8e7c5a0d2eaf5fd5" } ], "cards": [] }, { "type": "sections", "max_columns": 4, "title": "中控", "path": "control-center", "icon": "mdi:view-dashboard", "theme": "ios-dark-mode-light-blue", "sections": [ { "type": "grid", "column_span": 4, "cards": [ { "type": "picture", "image": { "media_content_id": "/local/images/lbxx.jpg", "media_content_type": "", "metadata": { "navigateIds": [ {}, { "media_content_type": "", "media_content_id": "__MANUAL_ENTRY__" } ] } }, "grid_options": { "rows": "auto", "columns": 4 } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:button-card", "show_icon": false, "show_name": false, "show_state": false, "grid_options": { "columns": 12, "row": 2 }, "custom_fields": { "greeting": "[[[\n const h = new Date().getHours();\n if (h < 6) return \"夜深了\";\n if (h < 11) return \"早上好\";\n if (h < 14) return \"晏昼好\";\n if (h < 18) return \"下午好\";\n return \"晚上好\";\n]]]\n", "clock": "[[[\n return new Date().toLocaleTimeString(\n 'zh-CN',\n { hour: '2-digit', minute: '2-digit', hour12: false }\n );\n]]]\n", "date": "[[[\n return new Date().toLocaleDateString(\n 'zh-CN',\n { month: 'long', day: 'numeric', weekday: 'long' }\n );\n]]]\n" }, "styles": { "card": [ { "height": "120px" }, { "padding": "20px 24px" }, { "border-radius": "24px" }, { "border": "none" }, { "background": "linear-gradient(135deg, rgba(32,35,42,0.95), rgba(20,22,27,0.95))" }, { "box-shadow": "none" } ], "grid": [ { "grid-template-areas": "\"greeting clock\"\n\"subtitle date\"\n" }, { "grid-template-columns": "1fr auto" }, { "grid-template-rows": "1fr 1fr" } ], "custom_fields": { "greeting": [ { "justify-self": "start" }, { "align-self": "end" }, { "font-size": "30px" }, { "font-weight": 700 }, { "color": "white" } ], "subtitle": [ { "justify-self": "start" }, { "align-self": "start" }, { "font-size": "14px" }, { "color": "rgba(255,255,255,0.55)" } ], "clock": [ { "justify-self": "end" }, { "align-self": "end" }, { "font-size": "32px" }, { "font-weight": 600 }, { "color": "white" } ], "date": [ { "justify-self": "end" }, { "align-self": "start" }, { "font-size": "14px" }, { "color": "rgba(255,255,255,0.55)" } ] } } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "sensor.lights_of_count", "icon": "mdi:lightbulb-group", "content": "{% if is_state('sensor.lights_of_count','0') %}\n \n{% else %}\n {{states('sensor.lights_of_count')}}\n{% endif %}" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================== */\n /* USER CONFIG HERE */\n /* ================================== */\n\n /* 1. ACTIVE STATE (NUMERIC) */\n {% set threshold_below = false %}\n {% set threshold_above = 1 %}\n\n /* 2. POSITIONING */\n {% set pos_y = 'bottom' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'left' %} \n {% set pos_x_val = '5px' %}\n\n /* 3. SIZING */\n {% set icon_size = '18px' %} \n {% set text_size = '12px' %} \n {% set badge_height = '5px' %} \n {% set border_radius = '10px' %} \n {% set border_thickness = '1px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#a63a3a' %} \n {% set active_icon = 'yellow' %}\n {% set active_text = 'white' %}\n {% set active_border = '#ab1c1c' %}\n {% set active_opacity = 0 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 2 %}\n {% set anim_delay_sec = 5 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set state_num = current_state | float(-99999) %}\n \n {% set check_below = threshold_below | string | lower != 'false' %}\n {% set check_above = threshold_above | string | lower != 'false' %}\n \n {% set is_active_below = check_below and state_num != -99999 and state_num <= (threshold_below | float(-99999)) %}\n {% set is_active_above = check_above and state_num != -99999 and state_num >= (threshold_above | float(-99999)) %}\n \n {% set is_active = is_active_below or is_active_above %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "sensor.aircondition_of_count", "icon": "mdi:air-conditioner", "content": "{% if is_state('sensor.aircondition_of_count','0') %}\n \n{% else %}\n {{states('sensor.aircondition_of_count')}}\n{% endif %}" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================== */\n /* USER CONFIG HERE */\n /* ================================== */\n\n /* 1. ACTIVE STATE (NUMERIC) */\n {% set threshold_below = false %}\n {% set threshold_above = 1 %}\n\n /* 2. POSITIONING */\n {% set pos_y = 'bottom' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'left' %} \n {% set pos_x_val = '40px' %}\n\n /* 3. SIZING */\n {% set icon_size = '18px' %} \n {% set text_size = '12px' %} \n {% set badge_height = '5px' %} \n {% set border_radius = '10px' %} \n {% set border_thickness = '1px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#a63a3a' %} \n {% set active_icon = '#42A5F5' %}\n {% set active_text = 'white' %}\n {% set active_border = '#ab1c1c' %}\n {% set active_opacity = 0 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 2 %}\n {% set anim_delay_sec = 5 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set state_num = current_state | float(-99999) %}\n \n {% set check_below = threshold_below | string | lower != 'false' %}\n {% set check_above = threshold_above | string | lower != 'false' %}\n \n {% set is_active_below = check_below and state_num != -99999 and state_num <= (threshold_below | float(-99999)) %}\n {% set is_active_above = check_above and state_num != -99999 and state_num >= (threshold_above | float(-99999)) %}\n \n {% set is_active = is_active_below or is_active_above %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.quan_wu_feng_shan", "icon": "mdi:fan", "content": "{% if is_state('fan.quan_wu_feng_shan','0') %}\n \n{% else %}\n {{states('fan.quan_wu_feng_shan')}}\n{% endif %}" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================== */\n /* USER CONFIG HERE */\n /* ================================== */\n\n /* 1. ACTIVE STATE (NUMERIC) */\n {% set threshold_below = false %}\n {% set threshold_above = 1 %}\n\n /* 2. POSITIONING */\n {% set pos_y = 'bottom' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'left' %} \n {% set pos_x_val = '75px' %}\n\n /* 3. SIZING */\n {% set icon_size = '18px' %} \n {% set text_size = '12px' %} \n {% set badge_height = '5px' %} \n {% set border_radius = '10px' %} \n {% set border_thickness = '1px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#a63a3a' %} \n {% set active_icon = '#42A5F5' %}\n {% set active_text = 'white' %}\n {% set active_border = '#ab1c1c' %}\n {% set active_opacity = 0 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 2 %}\n {% set anim_delay_sec = 5 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set state_num = current_state | float(-99999) %}\n \n {% set check_below = threshold_below | string | lower != 'false' %}\n {% set check_above = threshold_above | string | lower != 'false' %}\n \n {% set is_active_below = check_below and state_num != -99999 and state_num <= (threshold_below | float(-99999)) %}\n {% set is_active_above = check_above and state_num != -99999 and state_num >= (threshold_above | float(-99999)) %}\n \n {% set is_active = is_active_below or is_active_above %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } } ] } ] }, { "type": "grid", "column_span": 4, "cards": [ { "type": "custom:button-card", "entity": "weather.he_feng_tian_qi_heweather", "show_icon": false, "show_name": false, "show_state": false, "grid_options": { "columns": 6, "rows": 3 }, "custom_fields": { "weather_icon": "[[[\n const s = entity?.state;\n const isNight =\n states['sun.sun']?.state === 'below_horizon';\n\n if (s === 'sunny')\n return isNight ? '🌙' : '☀️';\n\n if (s === 'clear-night')\n return '🌙';\n\n if (s === 'cloudy')\n return '☁️';\n\n if (s === 'partlycloudy')\n return isNight ? '☁️' : '⛅';\n\n if (s === 'fog')\n return '🌫️';\n\n if (s === 'windy' || s === 'windy-variant')\n return '🌬️';\n\n if (s === 'rainy')\n return '🌧️';\n\n if (s === 'pouring')\n return '🌧️';\n\n if (s === 'lightning' || s === 'lightning-rainy')\n return '⛈️';\n\n if (s === 'hail')\n return '🌨️';\n\n if (s === 'snowy' || s === 'snowy-rainy')\n return '❄️';\n\n return '🌤️';\n]]]\n", "temp": "[[[\n const temp = Number(entity?.attributes?.temperature);\n\n return Number.isFinite(temp)\n ? `${Math.round(temp)}°`\n : '--°';\n]]]\n", "condition": "[[[\n const textEntity =\n states['sensor.he_feng_tian_qi_heweather_text'];\n\n if (\n textEntity &&\n !['unknown', 'unavailable'].includes(textEntity.state)\n ) {\n return textEntity.state;\n }\n\n const map = {\n sunny: '晴',\n 'clear-night': '晴',\n cloudy: '阴',\n partlycloudy: '多云',\n fog: '雾',\n rainy: '小雨',\n pouring: '大雨',\n lightning: '雷电',\n 'lightning-rainy': '雷雨',\n hail: '冰雹',\n snowy: '雪',\n 'snowy-rainy': '雨夹雪',\n windy: '有风',\n 'windy-variant': '大风'\n };\n\n return map[entity?.state] ?? '--';\n]]]\n", "forecast": "[[[\n const feelsLike =\n Number(entity?.attributes?.apparent_temperature);\n\n if (Number.isFinite(feelsLike)) {\n return `今天 · 体感 ${Math.round(feelsLike)}°`;\n }\n\n return '今天';\n]]]\n", "humidity": "[[[\n const humidity =\n Number(entity?.attributes?.humidity);\n\n return Number.isFinite(humidity)\n ? `湿度 ${Math.round(humidity)}%`\n : '湿度 --';\n]]]\n" }, "styles": { "card": [ { "height": "175px" }, { "border-radius": "24px" }, { "border": "none" }, { "padding": "22px" }, { "overflow": "hidden" }, { "background": "linear-gradient(\n 145deg,\n #334b68 0%,\n #23334a 55%,\n #172131 100%\n)\n" }, { "box-shadow": "none" } ], "grid": [ { "grid-template-areas": "\"weather_icon temp\"\n\"weather_icon condition\"\n\"forecast humidity\"\n" }, { "grid-template-columns": "1.3fr 1fr" }, { "grid-template-rows": "2fr 1fr 1fr" } ], "custom_fields": { "weather_icon": [ { "font-size": "74px" }, { "align-self": "center" }, { "justify-self": "center" }, { "animation": "weatherFloat 5s ease-in-out infinite" } ], "temp": [ { "font-size": "46px" }, { "font-weight": 700 }, { "justify-self": "start" }, { "align-self": "end" }, { "color": "white" } ], "condition": [ { "font-size": "17px" }, { "align-self": "start" }, { "justify-self": "start" }, { "color": "rgba(255,255,255,0.7)" } ], "forecast": [ { "font-size": "13px" }, { "align-self": "end" }, { "justify-self": "center" }, { "color": "rgba(255,255,255,0.6)" } ], "humidity": [ { "font-size": "13px" }, { "align-self": "end" }, { "justify-self": "start" }, { "color": "rgba(255,255,255,0.6)" } ] } }, "extra_styles": "@keyframes weatherFloat {\n 0% {\n transform: translateY(0px) scale(1);\n }\n\n 50% {\n transform: translateY(-6px) scale(1.03);\n }\n\n 100% {\n transform: translateY(0px) scale(1);\n }\n}\n" }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "tap_action": { "action": "toggle" }, "icon": "mdi:fan", "icon_color": "orange", "name": "餐桌扇", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'fan.shhf_cn_1129134246_sflt11_s_11_fan' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# -------- TRIGGER DECISION LOGIC -------- #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set sensor_entity = state_entity %}\n {% if states(sensor_entity) == active_value %}\n {% set trigger_active = true %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% endif %}\n {# ------ END TRIGGER DECISION LOGIC ------ #}\n\n {# Fan speed still based on THIS card's entity percentage #}\n {% set speed = state_attr(config.entity, 'percentage') | int(0) %}\n\n {% if trigger_active %}\n {% if speed == 0 and is_state(config.entity, 'off') %}\n --shape-animation: fan-ultra-idle 3s ease-in-out infinite;\n {% else %}\n {% set dur = 1.2 - (speed / 120) %}\n --shape-animation: fan-ultra-spin {{ [0.25, dur] | max | round(2) }}s linear infinite;\n {% endif %}\n --fan-warp-animation: fan-warp 1.4s ease-in-out infinite;\n --fan-stream-animation: fan-stream 1.6s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --fan-warp-animation: none;\n --fan-stream-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--fan-warp-animation);\n}\n\n.shape::after {\n mix-blend-mode: screen;\n animation: var(--fan-stream-animation);\n}\n\n@keyframes fan-ultra-spin {\n 0% {\n transform: rotate(0deg) scale(1);\n filter: drop-shadow(0 0 3px rgba(var(--rgb-{{ config.icon_color }}), 0.8));\n }\n 20% { transform: rotate(72deg) scale(1.03); }\n 40% { transform: rotate(144deg) scale(1.05); }\n 60% { transform: rotate(216deg) scale(1.03); }\n 80% { transform: rotate(288deg) scale(1.02); }\n 100% {\n transform: rotate(360deg) scale(1);\n filter: drop-shadow(0 0 5px rgba(var(--rgb-{{ config.icon_color }}), 1));\n }\n}\n\n@keyframes fan-ultra-idle {\n 0% { transform: rotate(-6deg); }\n 50% { transform: rotate(6deg); }\n 100% { transform: rotate(-6deg); }\n}\n\n@keyframes fan-warp {\n 0% {\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 40% {\n box-shadow:\n 0 0 0 8px rgba(var(--rgb-{{ config.icon_color }}), 0.4),\n 0 0 24px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 100% {\n box-shadow:\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 40px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes fan-stream {\n 0% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n 50% {\n box-shadow:\n 24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n -24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n\n /* 当前子卡片与其他子卡片的间距 */\n margin: 6px 2px !important;\n}\n" } } }, { "type": "custom:mushroom-entity-card", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "tap_action": { "action": "toggle" }, "icon": "mdi:fan", "icon_color": "cyan", "name": "小爱风扇", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = false %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'fan.xiaomi_cn_2196552583_p90_s_2_fan' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.plug_power' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n {# -------- TRIGGER DECISION LOGIC -------- #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {% set sensor_entity = state_entity %}\n {% if states(sensor_entity) == active_value %}\n {% set trigger_active = true %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% endif %}\n {# ------ END TRIGGER DECISION LOGIC ------ #}\n\n {# Fan speed still based on THIS card's entity percentage #}\n {% set speed = state_attr(config.entity, 'percentage') | int(0) %}\n\n {% if trigger_active %}\n {% if speed == 0 and is_state(config.entity, 'off') %}\n --shape-animation: fan-ultra-idle 3s ease-in-out infinite;\n {% else %}\n {% set dur = 1.2 - (speed / 120) %}\n --shape-animation: fan-ultra-spin {{ [0.25, dur] | max | round(2) }}s linear infinite;\n {% endif %}\n --fan-warp-animation: fan-warp 1.4s ease-in-out infinite;\n --fan-stream-animation: fan-stream 1.6s ease-in-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n --fan-warp-animation: none;\n --fan-stream-animation: none;\n opacity: 0.7;\n {% endif %}\n\n transform-origin: 50% 50%;\n position: relative;\n}\n\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n animation: var(--fan-warp-animation);\n}\n\n.shape::after {\n mix-blend-mode: screen;\n animation: var(--fan-stream-animation);\n}\n\n@keyframes fan-ultra-spin {\n 0% {\n transform: rotate(0deg) scale(1);\n filter: drop-shadow(0 0 3px rgba(var(--rgb-{{ config.icon_color }}), 0.8));\n }\n 20% { transform: rotate(72deg) scale(1.03); }\n 40% { transform: rotate(144deg) scale(1.05); }\n 60% { transform: rotate(216deg) scale(1.03); }\n 80% { transform: rotate(288deg) scale(1.02); }\n 100% {\n transform: rotate(360deg) scale(1);\n filter: drop-shadow(0 0 5px rgba(var(--rgb-{{ config.icon_color }}), 1));\n }\n}\n\n@keyframes fan-ultra-idle {\n 0% { transform: rotate(-6deg); }\n 50% { transform: rotate(6deg); }\n 100% { transform: rotate(-6deg); }\n}\n\n@keyframes fan-warp {\n 0% {\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 40% {\n box-shadow:\n 0 0 0 8px rgba(var(--rgb-{{ config.icon_color }}), 0.4),\n 0 0 24px 6px rgba(var(--rgb-{{ config.icon_color }}), 0.25);\n }\n 100% {\n box-shadow:\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 40px 12px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes fan-stream {\n 0% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n 50% {\n box-shadow:\n 24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.6),\n -24px 0 20px -10px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 100% {\n box-shadow:\n 20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0),\n -20px 0 16px -12px rgba(var(--rgb-{{ config.icon_color }}), 0);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n\n /* 当前子卡片与其他子卡片的间距 */\n margin: 6px 2px !important;\n}\n" } } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "icon": "mdi:minus", "tap_action": { "action": "perform-action", "perform_action": "fan.decrease_speed", "target": { "entity_id": "fan.xiaomi_cn_2196552583_p90_s_2_fan" }, "data": { "percentage_step": 5 } } } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'bottom' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '85px' %}\n\n /* 3. SIZING */\n {% set icon_size = '32px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '10px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = 'rgba(66, 165, 245, 0.3)' %} \n {% set active_icon = 'rgb(144, 202, 249)' %}\n {% set active_text = 'white' %}\n {% set active_border = 'white' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state in active_states %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "icon": "mdi:plus", "tap_action": { "action": "perform-action", "perform_action": "fan.increase_speed", "target": { "entity_id": "fan.xiaomi_cn_2196552583_p90_s_2_fan" }, "data": { "percentage_step": 5 } } } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'bottom' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '15px' %}\n\n /* 3. SIZING */\n {% set icon_size = '32px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '10px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = 'rgba(255, 167, 38, 0.3)' %} \n {% set active_icon = 'rgb(255, 204, 128)' %}\n {% set active_text = 'white' %}\n {% set active_border = 'white' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state in active_states %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "content": "{% set speed = state_attr(entity, 'percentage') %} {{ speed | int(0) }}%" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================== */\n /* USER CONFIG HERE */\n /* ================================== */\n\n /* 1. ACTIVE STATE (NUMERIC) */\n {% set threshold_below = 20 %}\n {% set threshold_above = false %}\n\n /* 2. POSITIONING */\n {% set pos_y = 'bottom' %} \n {% set pos_y_val = '22px' %}\n {% set pos_x = 'left' %} \n {% set pos_x_val = '140px' %}\n\n /* 3. SIZING */\n {% set icon_size = '18px' %} \n {% set text_size = '35px' %} \n {% set badge_height = '5px' %} \n {% set border_radius = '8px' %} \n {% set border_thickness = '1px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#a63a3a' %} \n {% set active_icon = 'white' %}\n {% set active_text = 'white' %}\n {% set active_border = '#ab1c1c' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'rgba(255, 167, 38, 0)' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 2 %}\n {% set anim_delay_sec = 5 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set state_num = current_state | float(-99999) %}\n \n {% set check_below = threshold_below | string | lower != 'false' %}\n {% set check_above = threshold_above | string | lower != 'false' %}\n \n {% set is_active_below = check_below and state_num != -99999 and state_num <= (threshold_below | float(-99999)) %}\n {% set is_active_above = check_above and state_num != -99999 and state_num >= (threshold_above | float(-99999)) %}\n \n {% set is_active = is_active_below or is_active_above %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "icon": "mdi:minus", "tap_action": { "action": "perform-action", "perform_action": "fan.decrease_speed", "target": { "entity_id": "fan.shhf_cn_1129134246_sflt11_s_11_fan" } } } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '85px' %}\n\n /* 3. SIZING */\n {% set icon_size = '32px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '10px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = 'rgba(66, 165, 245, 0.3)' %} \n {% set active_icon = 'rgb(144, 202, 249)' %}\n {% set active_text = 'white' %}\n {% set active_border = 'white' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state in active_states %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "icon": "mdi:plus", "tap_action": { "action": "perform-action", "perform_action": "fan.increase_speed", "target": { "entity_id": "fan.shhf_cn_1129134246_sflt11_s_11_fan" } } } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================ */\n /* USER CONFIG HERE */\n /* ================================ */\n\n /* 1. ACTIVE STATES */\n {% set active_states = ['on'] %}\n \n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '15px' %}\n {% set pos_x = 'right' %} \n {% set pos_x_val = '15px' %}\n\n /* 3. SIZING */\n {% set icon_size = '32px' %} \n {% set text_size = '13px' %} \n {% set badge_height = '10px' %} \n {% set border_radius = '5px' %} \n {% set border_thickness = '0px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = 'rgba(255, 167, 38, 0.3)' %} \n {% set active_icon = 'rgb(255, 204, 128)' %}\n {% set active_text = 'white' %}\n {% set active_border = 'white' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'grey' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n \n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 1 %}\n {% set anim_delay_sec = 1 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set is_active = current_state in active_states %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "entity": "fan.shhf_cn_1129134246_sflt11_s_11_fan", "content": "{% set speed = state_attr(entity, 'percentage') %} {{ speed | int(0) }}%" } ], "alignment": "end", "card_mod": { "style": "ha-card {\n /* ================================== */\n /* USER CONFIG HERE */\n /* ================================== */\n\n /* 1. ACTIVE STATE (NUMERIC) */\n {% set threshold_below = 20 %}\n {% set threshold_above = false %}\n\n /* 2. POSITIONING */\n {% set pos_y = 'top' %} \n {% set pos_y_val = '22px' %}\n {% set pos_x = 'left' %} \n {% set pos_x_val = '140px' %}\n\n /* 3. SIZING */\n {% set icon_size = '18px' %} \n {% set text_size = '35px' %} \n {% set badge_height = '5px' %} \n {% set border_radius = '8px' %} \n {% set border_thickness = '1px' %}\n \n /* 4. COLORS (HEX, RGB, Color Name) */\n /* --- Active --- */\n {% set active_bg = '#a63a3a' %} \n {% set active_icon = 'white' %}\n {% set active_text = 'white' %}\n {% set active_border = '#ab1c1c' %}\n {% set active_opacity = 0.3 %}\n \n /* --- Inactive --- */\n {% set inactive_bg = 'rgba(255, 167, 38, 0)' %}\n {% set inactive_icon = 'grey' %}\n {% set inactive_text = 'darkgrey' %}\n {% set inactive_border = 'transparent' %}\n {% set inactive_opacity = 0.3 %}\n\n /* 5. ANIMATIONS */\n /* Options: pulse, shake, wobble */\n /* flash, heartbeat, swing, vibrate */\n \n {% set anim_type = 'none' %}\n\n /* true = 24/7, false = only when active */\n {% set always_animate = false %}\n \n {% set anim_intensity_sec = 0.5 %} /* 0.1 to 1 */\n {% set anim_duration_sec = 2 %}\n {% set anim_delay_sec = 5 %}\n\n /* ================================== */\n /* USER CONFIG END (DONT TOUCH BELOW) */\n /* ================================== */\n\n {% set current_state = states(config.chips[0].entity) %}\n {% set state_num = current_state | float(-99999) %}\n \n {% set check_below = threshold_below | string | lower != 'false' %}\n {% set check_above = threshold_above | string | lower != 'false' %}\n \n {% set is_active_below = check_below and state_num != -99999 and state_num <= (threshold_below | float(-99999)) %}\n {% set is_active_above = check_above and state_num != -99999 and state_num >= (threshold_above | float(-99999)) %}\n \n {% set is_active = is_active_below or is_active_above %}\n \n {% if is_active %}\n {% set current_bg = active_bg %}\n {% set current_icon = active_icon %}\n {% set current_text = active_text %}\n {% set current_border = active_border %}\n {% set current_op = active_opacity %}\n {% set current_anim = anim_type %}\n {% else %}\n {% set current_bg = inactive_bg %}\n {% set current_icon = inactive_icon %}\n {% set current_text = inactive_text %}\n {% set current_border = inactive_border %}\n {% set current_op = inactive_opacity %}\n {% set current_anim = anim_type if always_animate else 'none' %}\n {% endif %}\n\n {% set master_cycle = anim_duration_sec + anim_delay_sec %}\n {% set iterations = (anim_duration_sec / anim_intensity_sec) | round(0, 'floor') | int if anim_intensity_sec > 0 else 0 %}\n {% set step_percent = (anim_intensity_sec / master_cycle) * 100 if master_cycle > 0 else 0 %}\n\n --chip-padding: {{ badge_height }};\n --chip-border-radius: {{ border_radius }};\n \n --chip-border-width: 0px !important;\n --ha-card-border-width: 0px !important;\n \n --chip-box-shadow: 0 0 0 {{ border_thickness }} {{ current_border }} !important;\n\n --text-color: {{ current_icon }} !important;\n --color: {{ current_icon }} !important; \n --chip-background: color-mix(in srgb, {{ current_bg }}, transparent {{ (1 - current_op) * 100 }}%) !important;\n --chip-font-size: {{ text_size }} !important;\n --chip-icon-size: {{ icon_size }} !important; \n --mdc-icon-size: {{ icon_size }} !important; \n --chip-height: auto !important;\n --primary-text-color: {{ current_text }} !important;\n --secondary-text-color: {{ current_text }} !important;\n\n position: absolute !important;\n {{ pos_y }}: {{ pos_y_val }};\n {{ pos_x }}: {{ pos_x_val }};\n z-index: 1;\n border: none !important;\n border-radius: {{ border_radius }} !important;\n box-shadow: 0 4px 6px rgba(0,0,0,0.2);\n overflow: visible !important;\n will-change: transform; \n \n {% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n animation: anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {{ master_cycle }}s infinite linear;\n {% endif %}\n}\n\nha-state-icon, ha-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: {{ icon_size }} !important; \n height: {{ icon_size }} !important;\n}\n\n{% if config.chips[0].content is not defined or config.chips[0].content | length == 0 %}\n ha-card { padding: 5px !important; border-radius: 50% !important; aspect-ratio: 1/1; justify-content: center; }\n .content { display: none; }\n{% else %}\n ha-card { padding: 0 10px !important; }\n .content { padding-left: 5px; font-weight: bold; }\n{% endif %}\n\n{% if current_anim != 'none' and iterations > 0 and master_cycle > 0 %}\n@keyframes anim-{{ config.chips[0].entity | replace('.', '-') }}-{{ anim_type }} {\n {% for i in range(iterations) %}\n {% set t = i * step_percent %} \n \n {% if anim_type == 'pulse' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'shake' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.25) }}% { transform: rotateZ(-10deg); }\n {{ t + (step_percent * 0.75) }}% { transform: rotateZ(10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'flash' %}\n {{ t + 0 }}% { opacity: 1; }\n {{ t + (step_percent * 0.5) }}% { opacity: 0; }\n {{ t + step_percent }}% { opacity: 1; }\n\n {% elif anim_type == 'wobble' %}\n {{ t + 0 }}% { transform: translate3d(0%, 0, 0); }\n {{ t + (step_percent * 0.3) }}% { transform: translate3d(-15%, 0, 0) rotateZ(-5deg); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(10%, 0, 0) rotateZ(3deg); }\n {{ t + step_percent }}% { transform: translate3d(0%, 0, 0); }\n\n {% elif anim_type == 'heartbeat' %}\n {{ t + 0 }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.25) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + (step_percent * 0.5) }}% { transform: scale3d(1, 1, 1); }\n {{ t + (step_percent * 0.75) }}% { transform: scale3d(1.15, 1.15, 1); }\n {{ t + step_percent }}% { transform: scale3d(1, 1, 1); }\n\n {% elif anim_type == 'swing' %}\n {{ t + 0 }}% { transform: rotateZ(0deg); }\n {{ t + (step_percent * 0.4) }}% { transform: rotateZ(15deg); }\n {{ t + (step_percent * 0.8) }}% { transform: rotateZ(-10deg); }\n {{ t + step_percent }}% { transform: rotateZ(0deg); }\n\n {% elif anim_type == 'vibrate' %}\n {{ t + 0 }}% { transform: translate3d(0, 0, 0); }\n {{ t + (step_percent * 0.2) }}% { transform: translate3d(-2px, 2px, 0); }\n {{ t + (step_percent * 0.4) }}% { transform: translate3d(-2px, -2px, 0); }\n {{ t + (step_percent * 0.6) }}% { transform: translate3d(2px, 2px, 0); }\n {{ t + (step_percent * 0.8) }}% { transform: translate3d(2px, -2px, 0); }\n {{ t + step_percent }}% { transform: translate3d(0, 0, 0); }\n\n {% endif %}\n {% endfor %}\n}\n{% endif %}\n" } } ], "card_mod": { "style": "ha-card {\n /* 整张组合卡片的背景颜色与透明度 */\n background: rgba(30, 30, 30, 0.1) !important;\n\n /* 整张组合卡片与周围其他卡片的距离 */\n /*margin: 10px 8px 16px 8px !important;*/\n\n /* 组合卡片边缘与内部卡片之间的距离 */\n padding: 2px 4px !important;\n}\n" }, "grid_options": { "columns": 10 } }, { "square": false, "type": "grid", "cards": [ { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_temperature_p_2_1", "tap_action": { "action": "more-info" }, "icon": "mdi:thermometer", "name": "温度", "primary_info": "state", "secondary_info": "name", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== CONFIG ========== #}\n {# == Updated: entity auto generated == #}\n {% set temp = states(config.entity) | float(0) %}\n\n {# ------------------------------------------- #}\n {# TEMPERATURE → COLOR + EFFECT PRESETS #}\n {# ------------------------------------------- #}\n\n {# DEFAULTS (will be overridden by ranges) #}\n {% set rgb = '0,140,255' %}\n {% set anim = 'temp-cold-breathe' %}\n {% set glow_anim = 'temp-cold-glow' %}\n {% set halo_anim = 'temp-cold-halo' %}\n {% set duration = 4.0 %}\n {% set intensity = 0.5 %}\n\n {# RANGES / COLORS #}\n {# You can change temp numbers below if needed #}\n\n {% if temp < 16 %}\n {# BLUE #}\n {% set rgb = '0,140,255' %}\n {% set anim = 'temp-cold-breathe' %}\n {% set glow_anim = 'temp-cold-glow' %}\n {% set halo_anim = 'temp-cold-halo' %}\n {% set duration = 4.4 %}\n {% set intensity = 0.4 %}\n\n {% elif temp < 18 %}\n {# YELLOW #}\n {% set rgb = '255,210,40' %}\n {% set anim = 'temp-cool-wave' %}\n {% set glow_anim = 'temp-cool-glow' %}\n {% set halo_anim = 'temp-cool-halo' %}\n {% set duration = 3.4 %}\n {% set intensity = 0.55 %}\n\n {% elif temp < 20 %}\n {# ORANGE #}\n {% set rgb = '255,150,40' %}\n {% set anim = 'temp-comfy-breathe' %}\n {% set glow_anim = 'temp-comfy-glow' %}\n {% set halo_anim = 'temp-comfy-halo' %}\n {% set duration = 3.0 %}\n {% set intensity = 0.6 %}\n\n {% elif temp < 22 %}\n {# DARK ORANGE #}\n {% set rgb = '255,115,20' %}\n {% set anim = 'temp-warm-pulse' %}\n {% set glow_anim = 'temp-warm-glow' %}\n {% set halo_anim = 'temp-warm-halo' %}\n {% set duration = 2.4 %}\n {% set intensity = 0.8 %}\n\n {% else %}\n {# RED #}\n {% set rgb = '255,40,40' %}\n {% set anim = 'temp-hot-shimmer' %}\n {% set glow_anim = 'temp-hot-glow' %}\n {% set halo_anim = 'temp-hot-halo' %}\n {% set duration = 2.0 %}\n {% set intensity = 1.0 %}\n {% endif %}\n\n {# Apply variables #}\n --temp-rgb: {{ rgb }};\n --temp-intensity: {{ intensity }};\n --shape-animation: {{ anim }} {{ duration }}s ease-in-out infinite;\n --temp-glow-animation: {{ glow_anim }} {{ (duration * 0.9) | round(2) }}s ease-in-out infinite;\n --temp-halo-animation: {{ halo_anim }} {{ (duration * 1.15) | round(2) }}s ease-in-out infinite;\n\n opacity: 1;\n\n /* Icon color follows the temperature */\n --icon-color: rgba({{ rgb }}, 1);\n\n /* KILL THE THEME BLUE & MAKE SHAPE NEUTRAL */\n background-color: rgba(77, 77, 77,0.1) !important;\n box-shadow: none !important;\n border: 1px solid rgba(255,255,255,0.06);\n\n position: relative;\n transform-origin: 50% 60%;\n animation: var(--shape-animation);\n}\n\n/* Glow layers */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n inset: -8px;\n animation: var(--temp-glow-animation);\n}\n\n.shape::after {\n inset: -22px;\n animation: var(--temp-halo-animation);\n mix-blend-mode: screen;\n}\n\n/* ========== COLD ========== */\n@keyframes temp-cold-breathe {\n 0% { transform: scale(0.96); }\n 50% { transform: scale(1.03); }\n 100% { transform: scale(0.96); }\n}\n\n@keyframes temp-cold-glow {\n 0% {\n box-shadow:\n 0 0 20px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 6 rgba(var(--temp-rgb), 0.55);\n }\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(var(--temp-rgb), 0.95),\n 0 0 50px 10px rgba(var(--temp-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 20px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 6 rgba(var(--temp-rgb), 0.55);\n }\n}\n\n@keyframes temp-cold-halo {\n 0% {\n box-shadow:\n 0 0 80px 20px rgba(var(--temp-rgb), 0.35),\n 0 -20px 80px -14px rgba(220, 240, 255, 0.55);\n }\n 50% {\n box-shadow:\n 0 0 130px 36px rgba(var(--temp-rgb), 0.5),\n 0 -34px 100px -8px rgba(240, 250, 255, 0.8);\n }\n 100% {\n box-shadow:\n 0 0 80px 20px rgba(var(--temp-rgb), 0.35),\n 0 -20px 80px -14px rgba(220, 240, 255, 0.55);\n }\n}\n\n/* ========== COOL ========== */\n@keyframes temp-cool-wave {\n 0% { transform: translateX(0); }\n 25% { transform: translateX(-1px); }\n 50% { transform: translateX(1px) translateY(-1px); }\n 75% { transform: translateX(-1px); }\n 100% { transform: translateX(0); }\n}\n\n@keyframes temp-cool-glow {\n 0% {\n box-shadow:\n 0 0 22px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 4 rgba(var(--temp-rgb), 0.7);\n }\n 50% {\n box-shadow:\n 0 0 28px 2 rgba(var(--temp-rgb), 0.95),\n 0 0 48px 12px rgba(var(--temp-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 22px 0 rgba(var(--temp-rgb), 0.6),\n 0 0 34px 4 rgba(var(--temp-rgb), 0.7);\n }\n}\n\n@keyframes temp-cool-halo {\n 0% {\n box-shadow:\n 0 0 90px 26px rgba(var(--temp-rgb), 0.35),\n 0 18px 80px -12px rgba(0, 220, 255, 0.35);\n }\n 50% {\n box-shadow:\n 0 0 140px 42px rgba(var(--temp-rgb), 0.45),\n 0 30px 110px -10px rgba(0, 255, 255, 0.5);\n }\n 100% {\n box-shadow:\n 0 0 90px 26px rgba(var(--temp-rgb), 0.35),\n 0 18px 80px -12px rgba(0, 220, 255, 0.35);\n }\n}\n\n/* ========== COMFY ========== */\n@keyframes temp-comfy-breathe {\n 0% { transform: scale(0.98); }\n 50% { transform: scale(1.05); }\n 100% { transform: scale(0.98); }\n}\n\n@keyframes temp-comfy-glow {\n 50% {\n box-shadow:\n 0 0 26px 4 rgba(var(--temp-rgb), 0.9),\n 0 0 42px 10px rgba(var(--temp-rgb), 0.85);\n }\n}\n\n@keyframes temp-comfy-halo {\n 50% {\n box-shadow:\n 0 0 120px 40px rgba(var(--temp-rgb), 0.45),\n 0 26px 80px -10px rgba(180,255,200,0.5);\n }\n}\n\n/* ========== WARM ========== */\n@keyframes temp-warm-pulse {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.07); }\n 100% { transform: scale(1); }\n}\n\n@keyframes temp-warm-glow {\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(var(--temp-rgb), 0.95),\n 0 0 54px 14px rgba(var(--temp-rgb), 0.9);\n }\n}\n\n@keyframes temp-warm-halo {\n 50% {\n box-shadow:\n 0 0 140px 48px rgba(var(--temp-rgb), 0.55),\n 0 26px 100px -10px rgba(255,210,150,0.5);\n }\n}\n\n/* ========== HOT ========== */\n@keyframes temp-hot-shimmer {\n 0% { transform: scale(1); filter: blur(0); }\n 50% { transform: scale(1.08); filter: blur(0.6px); }\n 100% { transform: scale(1); filter: blur(0); }\n}\n\n@keyframes temp-hot-glow {\n 50% {\n box-shadow:\n 0 0 34px 6 rgba(var(--temp-rgb), 1),\n 0 0 62px 14px rgba(var(--temp-rgb), 0.95);\n }\n}\n\n@keyframes temp-hot-halo {\n 50% {\n box-shadow:\n 0 0 160px 60px rgba(var(--temp-rgb), 0.6),\n 0 34px 120px -12px rgba(255,150,100,0.6);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 48px;\n --icon-color: rgba(var(--hum-rgb),1) !important;\n display: flex;\n margin: -16px 0 10px -20px !important;\n padding-right: 22px;\n padding-bottom: 18px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n \n /* FONT SIZE & SPACING SETTINGS */\n --card-primary-font-size: 1.4rem !important;\n \n /* Increases vertical space between primary and secondary */\n --card-primary-line-height: 1.3 !important;\n}\n" } } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mini-graph-card", "entities": [ "sensor.xiaomi_cn_blt_3_1ni9qhv584c03_mini_temperature_p_2_1001" ], "hours_to_show": 24, "line_width": 5, "show": { "name": false, "icon": false, "state": false, "labels": false, "legend": false }, "color_thresholds": [ { "value": 0, "color": "blue" }, { "value": 16, "color": "lightblue" }, { "value": 18, "color": "orange" }, { "value": 21, "color": "red" } ], "card_mod": { "style": "ha-card {\n background: none;\n box-shadow: none;\n opacity: 50%;\n border: none;\n width: 250px;\n mask-image: radial-gradient(\n ellipse at center,\n rgba(0,0,0,1) 0%,\n rgba(0,0,0,0) 90%\n );\n}\n" } } ], "card_mod": { "style": { ".": "ha-card {\n background: none;\n box-shadow: none;\n border: none;\n margin: 8px 12px; \n position: absolute;\n bottom: -10px;\n right: -10px;\n }\n" } } } ] }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mushroom-entity-card", "entity": "sensor.miaomiaoc_cn_blt_3_1ndt1bnq04c04_t1_relative_humidity_p_2_2", "tap_action": { "action": "more-info" }, "icon": "mdi:water-percent", "name": "湿度", "primary_info": "state", "secondary_info": "name", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== CONFIG ========== #}\n {# == Updated: entity auto generated == #}\n {% set hum = states(config.entity) | float(0) %}\n\n {# DEFAULTS #}\n {% set rgb = '120,210,255' %}\n {% set anim = 'hum-good-breathe' %}\n {% set glow_anim = 'hum-good-glow' %}\n {% set halo_anim = 'hum-good-halo' %}\n {% set duration = 3.2 %}\n\n {# RANGES\n < 40 -> BAD (dark blue)\n 40-60 -> GOOD (light blue)\n > 60 -> MIDDLE / humid (medium blue)\n #}\n\n {% if hum < 40 %}\n {# BAD - dry - dark blue #}\n {% set rgb = '0,80,200' %}\n {% set anim = 'hum-bad-pulse' %}\n {% set glow_anim = 'hum-bad-glow' %}\n {% set halo_anim = 'hum-bad-halo' %}\n {% set duration = 2.8 %}\n {% elif hum <= 60 %}\n {# GOOD - light blue #}\n {% set rgb = '120,210,255' %}\n {% set anim = 'hum-good-breathe' %}\n {% set glow_anim = 'hum-good-glow' %}\n {% set halo_anim = 'hum-good-halo' %}\n {% set duration = 3.4 %}\n {% else %}\n {# MIDDLE / humid - medium blue #}\n {% set rgb = '40,140,255' %}\n {% set anim = 'hum-mid-wave' %}\n {% set glow_anim = 'hum-mid-glow' %}\n {% set halo_anim = 'hum-mid-halo' %}\n {% set duration = 3.0 %}\n {% endif %}\n\n --hum-rgb: {{ rgb }};\n --shape-animation: {{ anim }} {{ duration }}s ease-in-out infinite;\n --hum-glow-animation: {{ glow_anim }} {{ (duration * 0.9) | round(2) }}s ease-in-out infinite;\n --hum-halo-animation: {{ halo_anim }} {{ (duration * 1.1) | round(2) }}s ease-in-out infinite;\n\n /* Icon color follows humidity color */\n --icon-color: rgba({{ rgb }}, 1);\n\n /* Neutral pill so theme blue does not leak through */\n background-color: rgba(77,77,77,0.2) !important;\n box-shadow: none !important;\n border: 1px solid rgba(255,255,255,0.06);\n\n opacity: 1;\n position: relative;\n transform-origin: 50% 60%;\n animation: var(--shape-animation);\n}\n\n/* Glow layers */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n inset: -8px;\n animation: var(--hum-glow-animation);\n}\n\n.shape::after {\n inset: -22px;\n animation: var(--hum-halo-animation);\n mix-blend-mode: screen;\n}\n\n/* ========== GOOD - light blue ========== */\n@keyframes hum-good-breathe {\n 0% { transform: scale(0.98); }\n 50% { transform: scale(1.04); }\n 100% { transform: scale(0.98); }\n}\n\n@keyframes hum-good-glow {\n 0% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.55),\n 0 0 30px 4 rgba(var(--hum-rgb), 0.6);\n }\n 50% {\n box-shadow:\n 0 0 24px 4 rgba(var(--hum-rgb), 0.9),\n 0 0 44px 10px rgba(var(--hum-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.55),\n 0 0 30px 4 rgba(var(--hum-rgb), 0.6);\n }\n}\n\n@keyframes hum-good-halo {\n 0% {\n box-shadow:\n 0 0 80px 24px rgba(var(--hum-rgb), 0.35),\n 0 18px 70px -12px rgba(180,230,255,0.3);\n }\n 50% {\n box-shadow:\n 0 0 120px 40px rgba(var(--hum-rgb), 0.45),\n 0 26px 90px -10px rgba(200,240,255,0.45);\n }\n 100% {\n box-shadow:\n 0 0 80px 24px rgba(var(--hum-rgb), 0.35),\n 0 18px 70px -12px rgba(180,230,255,0.3);\n }\n}\n\n/* ========== MIDDLE / humid - medium blue ========== */\n@keyframes hum-mid-wave {\n 0% { transform: translateX(0); }\n 25% { transform: translateX(-1px); }\n 50% { transform: translateX(1px) translateY(-1px); }\n 75% { transform: translateX(-1px); }\n 100% { transform: translateX(0); }\n}\n\n@keyframes hum-mid-glow {\n 0% {\n box-shadow:\n 0 0 20px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 32px 4 rgba(var(--hum-rgb), 0.7);\n }\n 50% {\n box-shadow:\n 0 0 28px 3 rgba(var(--hum-rgb), 0.95),\n 0 0 48px 10px rgba(var(--hum-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 20px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 32px 4 rgba(var(--hum-rgb), 0.7);\n }\n}\n\n@keyframes hum-mid-halo {\n 0% {\n box-shadow:\n 0 0 90px 26px rgba(var(--hum-rgb), 0.4),\n 0 18px 80px -12px rgba(80,190,255,0.35);\n }\n 50% {\n box-shadow:\n 0 0 135px 42px rgba(var(--hum-rgb), 0.5),\n 0 28px 105px -10px rgba(100,210,255,0.5);\n }\n 100% {\n box-shadow:\n 0 0 90px 26px rgba(var(--hum-rgb), 0.4),\n 0 18px 80px -12px rgba(80,190,255,0.35);\n }\n}\n\n/* ========== BAD - dry - dark blue ========== */\n@keyframes hum-bad-pulse {\n 0% { transform: scale(0.97); }\n 40% { transform: scale(1.03); }\n 100% { transform: scale(0.97); }\n}\n\n@keyframes hum-bad-glow {\n 0% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 28px 4 rgba(var(--hum-rgb), 0.7);\n }\n 50% {\n box-shadow:\n 0 0 26px 4 rgba(var(--hum-rgb), 0.95),\n 0 0 44px 12px rgba(var(--hum-rgb), 0.9);\n }\n 100% {\n box-shadow:\n 0 0 18px 0 rgba(var(--hum-rgb), 0.6),\n 0 0 28px 4 rgba(var(--hum-rgb), 0.7);\n }\n}\n\n@keyframes hum-bad-halo {\n 0% {\n box-shadow:\n 0 0 80px 22px rgba(var(--hum-rgb), 0.45),\n 0 18px 75px -10px rgba(0,70,160,0.5);\n }\n 50% {\n box-shadow:\n 0 0 130px 40px rgba(var(--hum-rgb), 0.6),\n 0 26px 100px -8px rgba(0,90,190,0.65);\n }\n 100% {\n box-shadow:\n 0 0 80px 22px rgba(var(--hum-rgb), 0.45),\n 0 18px 75px -10px rgba(0,70,160,0.5);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 48px;\n --icon-color: rgba(var(--hum-rgb),1) !important;\n display: flex;\n margin: -16px 0 10px -20px !important;\n padding-right: 22px;\n padding-bottom: 18px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n \n /* FONT SIZE & SPACING SETTINGS */\n --card-primary-font-size: 1.4rem !important;\n \n /* Increases vertical space between primary and secondary */\n --card-primary-line-height: 1.3 !important;\n}\n" } } }, { "type": "custom:vertical-stack-in-card", "cards": [ { "type": "custom:mini-graph-card", "entities": [ "sensor.xiaomi_cn_blt_3_1ni9qhv584c03_mini_relative_humidity_p_2_1002" ], "line_color": "lightblue", "line_width": 5, "hours_to_show": 24, "show": { "name": false, "icon": false, "state": false, "labels": false, "legend": false }, "card_mod": { "style": "ha-card {\n background: none;\n box-shadow: none;\n opacity: 50%;\n border: none;\n width: 250px;\n mask-image: radial-gradient(\n ellipse at center,\n rgba(0,0,0,1) 0%,\n rgba(0,0,0,0) 90%\n );\n}\n" } } ], "card_mod": { "style": { ".": "ha-card {\n background: none;\n box-shadow: none;\n border: none;\n margin: 8px 12px; \n position: absolute;\n bottom: -10px;\n right: -10px;\n }\n" } } } ] }, { "type": "custom:mushroom-entity-card", "entity": "sensor.xiaomi_cn_2005161482_va3_air_quality_p_3_3", "tap_action": { "action": "more-info" }, "icon": "mdi:air-filter", "name": "卧室", "primary_info": "state", "secondary_info": "name", "fill_container": false, "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== CONFIG ========== #}\n {% set voc = states('sensor.livingroom_air_quality_voc') | float(0) %}\n\n {# DEFAULTS (will be overridden by ranges) #}\n {% set rgb = '40,200,120' %}\n {% set anim = 'voc-clean-breathe' %}\n {% set glow_anim = 'voc-clean-glow' %}\n {% set halo_anim = 'voc-clean-halo' %}\n {% set duration = 4.0 %}\n {% set intensity = 0.5 %}\n\n {# RANGES / COLORS #}\n {# You can change numbers below if needed #}\n\n {% if voc < 100 %}\n {# GREEN #}\n {% set rgb = '40,200,120' %}\n {% set anim = 'voc-clean-breathe' %}\n {% set glow_anim = 'voc-clean-glow' %}\n {% set halo_anim = 'voc-clean-halo' %}\n {% set duration = 4.4 %}\n {% set intensity = 0.45 %}\n\n {% elif voc < 200 %}\n {# YELLOW-GREEN #}\n {% set rgb = '140,220,80' %}\n {% set anim = 'voc-good-wave' %}\n {% set glow_anim = 'voc-good-glow' %}\n {% set halo_anim = 'voc-good-halo' %}\n {% set duration = 3.6 %}\n {% set intensity = 0.55 %}\n\n {% elif voc < 300 %}\n {# YELLOW #}\n {% set rgb = '255,210,40' %}\n {% set anim = 'voc-fair-breathe' %}\n {% set glow_anim = 'voc-fair-glow' %}\n {% set halo_anim = 'voc-fair-halo' %}\n {% set duration = 3.0 %}\n {% set intensity = 0.7 %}\n\n {% elif voc < 400 %}\n {# ORANGE #}\n {% set rgb = '255,140,40' %}\n {% set anim = 'voc-poor-pulse' %}\n {% set glow_anim = 'voc-poor-glow' %}\n {% set halo_anim = 'voc-poor-halo' %}\n {% set duration = 2.4 %}\n {% set intensity = 0.9 %}\n\n {% else %}\n {# RED #}\n {% set rgb = '255,50,50' %}\n {% set anim = 'voc-bad-shimmer' %}\n {% set glow_anim = 'voc-bad-glow' %}\n {% set halo_anim = 'voc-bad-halo' %}\n {% set duration = 2.0 %}\n {% set intensity = 1.0 %}\n {% endif %}\n\n {# Apply variables #}\n --voc-rgb: {{ rgb }};\n --voc-intensity: {{ intensity }};\n --shape-animation: {{ anim }} {{ duration }}s ease-in-out infinite;\n --voc-glow-animation: {{ glow_anim }} {{ (duration * 0.9) | round(2) }}s ease-in-out infinite;\n --voc-halo-animation: {{ halo_anim }} {{ (duration * 1.15) | round(2) }}s ease-in-out infinite;\n\n opacity: 1;\n\n /* Icon color follows VOC level */\n --icon-color: rgba({{ rgb }}, 1);\n\n /* Shape neutral base */\n background-color: rgba(77, 77, 77,0.1) !important;\n box-shadow: none !important;\n border: 1px solid rgba(255,255,255,0.06);\n\n position: relative;\n transform-origin: 50% 60%;\n animation: var(--shape-animation);\n}\n\n/* Glow layers */\n.shape::before,\n.shape::after {\n content: '';\n position: absolute;\n border-radius: inherit;\n pointer-events: none;\n}\n\n.shape::before {\n inset: -8px;\n animation: var(--voc-glow-animation);\n}\n\n.shape::after {\n inset: -22px;\n animation: var(--voc-halo-animation);\n mix-blend-mode: screen;\n}\n\n/* ========== CLEAN ========== */\n@keyframes voc-clean-breathe {\n 0% { transform: scale(0.96); }\n 50% { transform: scale(1.03); }\n 100% { transform: scale(0.96); }\n}\n\n@keyframes voc-clean-glow {\n 0% {\n box-shadow:\n 0 0 20px 0 rgba(var(--voc-rgb), 0.55),\n 0 0 34px 6 rgba(var(--voc-rgb), 0.5);\n }\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(var(--voc-rgb), 0.9),\n 0 0 50px 10px rgba(var(--voc-rgb), 0.85);\n }\n 100% {\n box-shadow:\n 0 0 20px 0 rgba(var(--voc-rgb), 0.55),\n 0 0 34px 6 rgba(var(--voc-rgb), 0.5);\n }\n}\n\n@keyframes voc-clean-halo {\n 0% {\n box-shadow:\n 0 0 80px 20px rgba(var(--voc-rgb), 0.28),\n 0 -20px 80px -14px rgba(200, 255, 230, 0.45);\n }\n 50% {\n box-shadow:\n 0 0 130px 36px rgba(var(--voc-rgb), 0.42),\n 0 -34px 100px -8px rgba(220, 255, 240, 0.65);\n }\n 100% {\n box-shadow:\n 0 0 80px 20px rgba(var(--voc-rgb), 0.28),\n 0 -20px 80px -14px rgba(200, 255, 230, 0.45);\n }\n}\n\n/* ========== GOOD ========== */\n@keyframes voc-good-wave {\n 0% { transform: translateX(0); }\n 25% { transform: translateX(-1px); }\n 50% { transform: translateX(1px) translateY(-1px); }\n 75% { transform: translateX(-1px); }\n 100% { transform: translateX(0); }\n}\n\n@keyframes voc-good-glow {\n 0% {\n box-shadow:\n 0 0 22px 0 rgba(var(--voc-rgb), 0.55),\n 0 0 34px 4 rgba(var(--voc-rgb), 0.6);\n }\n 50% {\n box-shadow:\n 0 0 28px 2 rgba(var(--voc-rgb), 0.9),\n 0 0 48px 12px rgba(var(--voc-rgb), 0.8);\n }\n 100% {\n box-shadow:\n 0 0 22px 0 rgba(var(--voc-rgb), 0.55),\n 0 0 34px 4 rgba(var(--voc-rgb), 0.6);\n }\n}\n\n@keyframes voc-good-halo {\n 0% {\n box-shadow:\n 0 0 90px 26px rgba(var(--voc-rgb), 0.3),\n 0 18px 80px -12px rgba(140, 255, 120, 0.25);\n }\n 50% {\n box-shadow:\n 0 0 140px 42px rgba(var(--voc-rgb), 0.4),\n 0 30px 110px -10px rgba(160, 255, 140, 0.4);\n }\n 100% {\n box-shadow:\n 0 0 90px 26px rgba(var(--voc-rgb), 0.3),\n 0 18px 80px -12px rgba(140, 255, 120, 0.25);\n }\n}\n\n/* ========== FAIR ========== */\n@keyframes voc-fair-breathe {\n 0% { transform: scale(0.98); }\n 50% { transform: scale(1.05); }\n 100% { transform: scale(0.98); }\n}\n\n@keyframes voc-fair-glow {\n 50% {\n box-shadow:\n 0 0 26px 4 rgba(var(--voc-rgb), 0.85),\n 0 0 42px 10px rgba(var(--voc-rgb), 0.8);\n }\n}\n\n@keyframes voc-fair-halo {\n 50% {\n box-shadow:\n 0 0 120px 40px rgba(var(--voc-rgb), 0.42),\n 0 26px 80px -10px rgba(255, 245, 180, 0.5);\n }\n}\n\n/* ========== POOR ========== */\n@keyframes voc-poor-pulse {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.07); }\n 100% { transform: scale(1); }\n}\n\n@keyframes voc-poor-glow {\n 50% {\n box-shadow:\n 0 0 30px 4 rgba(var(--voc-rgb), 0.95),\n 0 0 54px 14px rgba(var(--voc-rgb), 0.9);\n }\n}\n\n@keyframes voc-poor-halo {\n 50% {\n box-shadow:\n 0 0 140px 48px rgba(var(--voc-rgb), 0.52),\n 0 26px 100px -10px rgba(255, 210, 150, 0.5);\n }\n}\n\n/* ========== BAD ========== */\n@keyframes voc-bad-shimmer {\n 0% { transform: scale(1); filter: blur(0); }\n 50% { transform: scale(1.08); filter: blur(0.6px); }\n 100% { transform: scale(1); filter: blur(0); }\n}\n\n@keyframes voc-bad-glow {\n 50% {\n box-shadow:\n 0 0 34px 6 rgba(var(--voc-rgb), 1),\n 0 0 62px 14px rgba(var(--voc-rgb), 0.95);\n }\n}\n\n@keyframes voc-bad-halo {\n 50% {\n box-shadow:\n 0 0 160px 60px rgba(var(--voc-rgb), 0.6),\n 0 34px 120px -12px rgba(255, 140, 120, 0.6);\n }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 48px;\n --icon-color: rgba(var(--voc-rgb),1) !important;\n display: flex;\n margin: -10px 0 10px -20px !important;\n padding-right: 22px;\n padding-bottom: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 14px));\n\n --card-primary-font-size: 1.5rem !important;\n --card-primary-line-height: 1.3 !important;\n}\n" } } }, { "type": "custom:mushroom-entity-card", "entity": "sensor.water_damage_count", "tap_action": { "action": "none" }, "icon": "mdi:water", "name": "水浸设备数", "card_mod": { "style": { "mushroom-shape-icon$": ".shape {\n {# ========== USER CONFIG ========== #}\n {# true = number mode, false = state mode #}\n {% set use_number = true %}\n\n {# STATE MODE SETTINGS #}\n {% set state_entity = 'switch.plug_6_local' %}\n {% set active_value = 'on' %}\n\n {# OPTIONAL: NUMBER MODE SETTINGS #}\n {% set number_entity = 'sensor.water_damage_count' %}\n \n {# '>' '<' '=' '>=' '<=' #}\n {% set number_operator = '>' %}\n \n {% set threshold = 0.0 %}\n {# ========== END USER CONFIG ====== #}\n\n\n {# ======== TRIGGER DECISION LOGIC ======== #}\n {% if use_number %}\n {% set num = states(number_entity) | float(0) %}\n {% if number_operator == '>' %}\n {% set trigger_active = (num > threshold) %}\n {% elif number_operator == '<' %}\n {% set trigger_active = (num < threshold) %}\n {% elif number_operator == '=' %}\n {% set trigger_active = (num == threshold) %}\n {% elif number_operator == '>=' %}\n {% set trigger_active = (num >= threshold) %}\n {% elif number_operator == '<=' %}\n {% set trigger_active = (num <= threshold) %}\n {% else %}\n {% set trigger_active = false %}\n {% endif %}\n {% else %}\n {# default: simple equality state trigger #}\n {% set trigger_active = (states(state_entity) == active_value) %}\n {% endif %}\n {# =========== END TRIGGER LOGIC =========== #}\n\n\n {% if trigger_active %}\n --shape-animation: doorbell-ring 0.9s ease-out infinite;\n opacity: 1;\n {% else %}\n --shape-animation: none;\n opacity: 0.8;\n {% endif %}\n\n transform-origin: 50% 50%;\n}\n\n@keyframes doorbell-ring {\n 0% {\n transform: scale(1.05);\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 1),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.8),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 30% {\n transform: scale(0.95);\n box-shadow:\n 0 0 0 4px rgba(var(--rgb-{{ config.icon_color }}), 0.9),\n 0 0 0 10px rgba(var(--rgb-{{ config.icon_color }}), 0.7),\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.4);\n }\n 60% {\n transform: scale(1.02);\n box-shadow:\n 0 0 0 10px rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 0 18px rgba(var(--rgb-{{ config.icon_color }}), 0.2),\n 0 0 0 26px rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n 100% {\n transform: scale(1);\n box-shadow:\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.0),\n 0 0 0 0 rgba(var(--rgb-{{ config.icon_color }}), 0.0);\n }\n}\n\n@keyframes doorbell-idle {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.03); }\n 100% { transform: scale(1); }\n}\n", ".": "mushroom-shape-icon {\n --icon-size: 65px;\n display: flex;\n margin: -18px 0 10px -20px !important;\n padding-right: 10px;\n}\nha-card {\n clip-path: inset(0 0 0 0 round var(--ha-card-border-radius, 12px));\n}\n" } } } ], "columns": 2 } ] }, { "type": "grid", "column_span": 4, "cards": [ { "type": "heading", "heading": "快捷控制", "icon": "mdi:lightning-bolt", "heading_style": "title" }, { "type": "custom:mushroom-template-card", "entity": "light.quan_wu_zhao_ming", "primary": "全屋灯光", "secondary": "{% set n = states('sensor.lights_of_count') | int(0) %} {% if n > 0 %}{{ n }} 盏开启{% else %}全部关闭{% endif %}\n", "icon": "mdi:lightbulb-group", "icon_color": "{% if states('sensor.lights_of_count') | int(0) > 0 %}amber{% else %}grey{% endif %}\n", "tap_action": { "action": "more-info" }, "hold_action": { "action": "toggle" }, "grid_options": { "columns": 4, "rows": 1 } }, { "type": "custom:mushroom-template-card", "entity": "climate.qdhkl_cn_2113954983_b19c", "primary": "空调", "secondary": "{% if is_state(config.entity,'off') %}\n 已关闭\n{% else %}\n {{ state_attr(config.entity,'temperature') }}°C\n{% endif %}\n", "icon": "mdi:snowflake", "icon_color": "{% if is_state(config.entity,'off') %}grey{% else %}blue{% endif %}\n", "tap_action": { "action": "more-info" }, "grid_options": { "columns": 4, "rows": 1 } }, { "type": "custom:mushroom-template-card", "entity": "fan.xiaomi_cn_2005161482_va3_s_2_air_purifier", "primary": "空气净化器", "secondary": "{% if is_state(config.entity,'on') %}运行中{% else %}已关闭{% endif %}\n", "icon": "mdi:air-purifier", "icon_color": "{% if is_state(config.entity,'on') %}cyan{% else %}grey{% endif %}\n", "tap_action": { "action": "toggle" }, "hold_action": { "action": "more-info" }, "grid_options": { "columns": 5, "rows": 1 } }, { "type": "custom:mushroom-template-card", "entity": "fan.xiaomi_cn_2196552583_p90_s_2_fan", "primary": "风扇", "secondary": "{% if is_state(config.entity,'on') %}运行中{% else %}已关闭{% endif %}\n", "icon": "mdi:fan", "icon_color": "{% if is_state(config.entity,'on') %}light-blue{% else %}grey{% endif %}\n", "tap_action": { "action": "toggle" }, "hold_action": { "action": "more-info" }, "grid_options": { "columns": 4, "rows": 1 } }, { "type": "custom:mushroom-template-card", "entity": "cover.panpan_cn_876603548_y18_s_2_airer", "primary": "晾衣架", "secondary": "{{ states(config.entity) }}\n", "icon": "mdi:hanger", "icon_color": "teal", "tap_action": { "action": "more-info" }, "grid_options": { "columns": 4, "rows": 1 } }, { "type": "custom:mushroom-template-card", "entity": "switch.cuco_cn_2006579195_v3_on_p_2_1", "primary": "NAS", "secondary": "{{ states('sensor.cuco_cn_2006579195_v3_electric_power_p_11_2') }} W\n", "icon": "mdi:nas", "icon_color": "{% if is_state(config.entity,'on') %}red{% else %}grey{% endif %}\n", "tap_action": { "action": "navigate", "navigation_path": "home-server" }, "grid_options": { "columns": 4, "rows": 1 } } ] }, { "type": "grid", "column_span": 4, "cards": [ { "type": "heading", "heading": "房间灯光", "icon": "mdi:floor-plan", "heading_style": "title" }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1187112198_xsx340_s_2", "name": "客厅", "icon": "mdi:sofa", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "grid_options": { "columns": 6, "rows": 2 } }, { "type": "custom:mushroom-light-card", "entity": "light.shhf_cn_1129134246_sflt11_s_2_light", "name": "餐桌", "icon": "mdi:table-chair", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "grid_options": { "columns": 6, "rows": 2 } }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1186735998_xsx340_s_2", "name": "主卧", "icon": "mdi:bed-king", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "grid_options": { "columns": 6, "rows": 2 } }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1186772227_xsx340_s_2", "name": "次卧", "icon": "mdi:bed-single", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "grid_options": { "columns": 6, "rows": 2 } }, { "type": "custom:mushroom-light-card", "entity": "light.pmfbj_cn_1186744390_xsx340_s_2", "name": "书房", "icon": "mdi:desk", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "grid_options": { "columns": 6, "rows": 2 } }, { "type": "custom:mushroom-light-card", "entity": "light.opple_cn_2005385416_moat_s_2_light", "name": "阳台", "icon": "mdi:balcony", "use_light_color": true, "show_brightness_control": true, "show_color_temp_control": true, "grid_options": { "columns": 6, "rows": 2 } } ] } ], "header": { "layout": "responsive", "badges_position": "bottom", "badges_wrap": "wrap" }, "background": { "opacity": 80, "alignment": "center", "size": "cover", "repeat": "repeat", "attachment": "fixed" }, "cards": [] }, { "title": "首页", "path": "home", "icon": "mdi:home", "type": "sections", "max_columns": 4, "sections": [ { "type": "grid", "cards": [ { "type": "custom:button-card", "show_icon": false, "show_name": false, "show_state": false, "grid_options": { "columns": 12, "rows": 2 }, "custom_fields": { "greeting": "[[[\n const h = new Date().getHours();\n if (h < 6) return \"夜深了\";\n if (h < 11) return \"早上好\";\n if (h < 14) return \"中午好\";\n if (h < 18) return \"下午好\";\n return \"晚上好\";\n]]]\n", "clock": "[[[\n return new Date().toLocaleTimeString(\n 'zh-CN',\n {\n hour: '2-digit',\n minute: '2-digit',\n hour12: false\n }\n );\n]]]\n", "date": "[[[\n return new Date().toLocaleDateString(\n 'zh-CN',\n {\n month: 'long',\n day: 'numeric',\n weekday: 'long'\n }\n );\n]]]\n", "subtitle": "家里一切正常\n" }, "styles": { "card": [ { "height": "130px" }, { "padding": "20px 24px" }, { "border-radius": "24px" }, { "border": "none" }, { "background": "linear-gradient(\n 135deg,\n rgba(32,35,42,0.95),\n rgba(20,22,27,0.95)\n)\n" }, { "box-shadow": "none" } ], "grid": [ { "grid-template-areas": "\"greeting clock\"\n\"subtitle date\"\n" }, { "grid-template-columns": "1fr auto" }, { "grid-template-rows": "1fr 1fr" } ], "custom_fields": { "greeting": [ { "justify-self": "start" }, { "align-self": "end" }, { "font-size": "30px" }, { "font-weight": 700 }, { "color": "white" } ], "subtitle": [ { "justify-self": "start" }, { "align-self": "start" }, { "font-size": "14px" }, { "color": "rgba(255,255,255,0.55)" } ], "clock": [ { "justify-self": "end" }, { "align-self": "end" }, { "font-size": "32px" }, { "font-weight": 600 }, { "color": "white" } ], "date": [ { "justify-self": "end" }, { "align-self": "start" }, { "font-size": "14px" }, { "color": "rgba(255,255,255,0.55)" } ] } } } ] }, { "type": "grid", "cards": [ { "type": "custom:button-card", "entity": "weather.home", "show_icon": false, "show_name": false, "show_state": false, "grid_options": { "columns": 6, "rows": 4 }, "custom_fields": { "weather_icon": "[[[\n const s = entity?.state;\n\n if (s === \"sunny\")\n return \"☀️\";\n\n if (s === \"clear-night\")\n return \"🌙\";\n\n if (s === \"cloudy\")\n return \"☁️\";\n\n if (s === \"partlycloudy\")\n return \"⛅\";\n\n if ([\"rainy\",\"pouring\"].includes(s))\n return \"🌧️\";\n\n if (s === \"lightning\")\n return \"⛈️\";\n\n return \"🌤️\";\n]]]\n", "temp": "[[[\n const temp =\n states['sensor.outdoor_temperature']?.state ?? '--';\n\n return `${temp}°`;\n]]]\n", "condition": "[[[\n const map = {\n sunny: \"晴\",\n cloudy: \"多云\",\n partlycloudy: \"局部多云\",\n rainy: \"下雨\",\n pouring: \"大雨\",\n \"clear-night\": \"晴朗\"\n };\n\n return map[entity?.state] ?? entity?.state ?? \"--\";\n]]]\n", "forecast": "[[[\n return \"今天 · 舒适\";\n]]]\n", "humidity": "[[[\n const hum =\n states['sensor.outdoor_humidity']?.state ?? '--';\n\n return `湿度 ${hum}%`;\n]]]\n" }, "styles": { "card": [ { "height": "210px" }, { "border-radius": "24px" }, { "border": "none" }, { "padding": "22px" }, { "overflow": "hidden" }, { "background": "linear-gradient(\n 145deg,\n #334b68 0%,\n #23334a 55%,\n #172131 100%\n)\n" }, { "box-shadow": "none" } ], "grid": [ { "grid-template-areas": "\"weather_icon temp\"\n\"weather_icon condition\"\n\"forecast humidity\"\n" }, { "grid-template-columns": "1fr 1.3fr" }, { "grid-template-rows": "1fr auto auto" } ], "custom_fields": { "weather_icon": [ { "font-size": "74px" }, { "align-self": "center" }, { "justify-self": "center" }, { "animation": "weatherFloat 5s ease-in-out infinite" } ], "temp": [ { "font-size": "46px" }, { "font-weight": 700 }, { "justify-self": "start" }, { "align-self": "end" }, { "color": "white" } ], "condition": [ { "font-size": "17px" }, { "justify-self": "start" }, { "color": "rgba(255,255,255,0.7)" } ], "forecast": [ { "font-size": "13px" }, { "justify-self": "start" }, { "color": "rgba(255,255,255,0.6)" } ], "humidity": [ { "font-size": "13px" }, { "justify-self": "end" }, { "color": "rgba(255,255,255,0.6)" } ] } }, "extra_styles": "@keyframes weatherFloat {\n 0% {\n transform: translateY(0px) scale(1);\n }\n\n 50% {\n transform: translateY(-6px) scale(1.03);\n }\n\n 100% {\n transform: translateY(0px) scale(1);\n }\n}\n" }, { "type": "custom:button-card", "show_icon": false, "show_name": false, "grid_options": { "columns": 6, "rows": 4 }, "custom_fields": { "title": "家庭状态", "temperature": "[[[\n return `\n