diff --git a/.storage/lovelace b/.storage/lovelace
index 74080fc..68d4dff 100644
--- a/.storage/lovelace
+++ b/.storage/lovelace
@@ -3,24 +3,52 @@
"config": {
"resources": [
{
- "type": "js",
- "url": "/local/plugins/lovelace-card-modder/card-modder.js?v=1"
+ "type": "module",
+ "url": "/community_plugin/mini-media-player/mini-media-player.js"
},
{
"type": "js",
- "url": "/local/plugins/lovelace-card-tools/card-tools.js?v=1"
+ "url": "/community_plugin/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js"
},
{
"type": "js",
- "url": "/local/plugins/lovelace-auto-entities/auto-entities.js?v=1"
+ "url": "/community_plugin/lovelace-slider-entity-row/slider-entity-row.js"
},
{
"type": "js",
- "url": "/local/plugins/lovelace-fold-entity-row/fold-entity-row.js?v=1"
+ "url": "/community_plugin/lovelace-layout-card/layout-card.js"
},
{
"type": "js",
- "url": "/local/plugins/lovelace-layout-card/layout-card.js?v=1"
+ "url": "/community_plugin/lovelace-multiple-entity-row/multiple-entity-row.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/secondaryinfo-entity-row/secondaryinfo-entity-row.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/entity-attributes-card/entity-attributes-card.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/vertical-stack-in-card/vertical-stack-in-card.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/lovelace-card-tools/card-tools.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/monster-card/monster-card.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/lovelace-fold-entity-row/fold-entity-row.js"
+ },
+ {
+ "type": "js",
+ "url": "/community_plugin/lovelace-auto-entities/auto-entities.js"
}
],
"title": "Hogar",
@@ -29,195 +57,424 @@
"badges": [],
"cards": [
{
- "entities": [
+ "cards": [
{
- "entity": "sensor.qubino_zmnhtdx_smart_meter_s4_s5_s6_power",
- "name": "Consumo el\u00e9ctrico"
+ "entities": [
+ {
+ "entity": "sensor.qubino_zmnhtdx_smart_meter_s4_s5_s6_power",
+ "name": "Consumo El\u00e9ctrico"
+ },
+ {
+ "entities": [
+ "sensor.temperatura_salon",
+ "sensor.temperatura_exterior",
+ {
+ "entities": [
+ "sensor.temperatura_salon",
+ "sensor.temperatura_exterior"
+ ],
+ "hours_to_show": 96,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": "sensor.temperatura_salon",
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entity": "fan.xiaomi_miio_device_2",
+ "name": "Purificador de Aire",
+ "primary": {
+ "entity": "binary_sensor.popp_smoke_detector_and_siren_sensor",
+ "name": "Calidad del Aire"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ },
+ {
+ "entity": "sensor.openweather_coslada",
+ "name": "Tiempo Exterior"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "sensor.wireless_router_archer_c7_kbyte_sec_received",
+ "name": "kbytes/sec recibidos"
+ },
+ {
+ "entity": "sensor.wireless_router_archer_c7_kbyte_sec_sent",
+ "name": "kbytes/sec enviados"
+ }
+ ],
+ "hours_to_show": 2,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "sensor.wireless_router_archer_c7_kbyte_sec_received",
+ "hide_state": true,
+ "name": "Tranferencia",
+ "primary": {
+ "entity": "sensor.wireless_router_archer_c7_kbyte_sec_received",
+ "name": "Recibido"
+ },
+ "secondary": {
+ "entity": "sensor.wireless_router_archer_c7_kbyte_sec_sent",
+ "name": "Enviado"
+ },
+ "type": "custom:multiple-entity-row"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "type": "entities"
},
{
- "entity": "sensor.temperatura_salon"
+ "card": {
+ "title": "Luces Encendidas & Desactivadas",
+ "type": "entities"
+ },
+ "filter": {
+ "exclude": [
+ {
+ "options": {
+ "secondary_info": "last-changed",
+ "tap_action": {
+ "action": "toggle"
+ }
+ },
+ "state": "off"
+ }
+ ],
+ "include": [
+ {
+ "domain": "light"
+ }
+ ]
+ },
+ "show_empty": false,
+ "type": "custom:auto-entities"
},
{
- "entity": "sensor.temperatura_exterior"
+ "card": {
+ "title": "Movimiento Activo",
+ "type": "entities"
+ },
+ "filter": {
+ "include": [
+ {
+ "entity_id": "binary_sensor.mov*",
+ "options": {
+ "secondary_info": "last-changed"
+ },
+ "state": "on"
+ }
+ ]
+ },
+ "show_empty": false,
+ "type": "custom:auto-entities"
+ },
+ "break",
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_pasillo_entrada"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_pasillo_entrada",
+ "name": "Entrada",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_cocina"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_cocina",
+ "name": "Cocina",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_salon_entrada"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_salon_entrada",
+ "name": "Entrada Sal\u00f3n",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_principal"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_principal",
+ "name": "H. Principal",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_noha"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_noha",
+ "name": "H. Noha",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_mia"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_mia",
+ "name": "H. Mia",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_estudio"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_estudio",
+ "name": "H. Estudio",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_pasillo_habitaciones"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_pasillo_habitaciones",
+ "name": "P. Habitaciones",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "head": {
+ "label": "Movimientos",
+ "type": "section"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.puerta_entrada"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.puerta_entrada",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.puerta_tendedero"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.puerta_tendedero",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "head": {
+ "label": "Puertas",
+ "type": "section"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entity": "cover.persiana_habitacion_principal",
+ "name": "Principal"
+ },
+ {
+ "entity": "cover.persiana_habitacion_noha",
+ "name": "Noha"
+ },
+ {
+ "entity": "cover.persiana_habitacion_mia",
+ "name": "Mia"
+ },
+ {
+ "entity": "cover.persiana_habitacion_estudio",
+ "name": "Estudio"
+ },
+ {
+ "entity": "cover.persiana_salon_fase_dos",
+ "name": "Fase Dos"
+ },
+ {
+ "entity": "cover.persiana_salon_piscina",
+ "name": "Piscina"
+ }
+ ],
+ "group_config": {
+ "type": "custom:slider-entity-row"
+ },
+ "head": {
+ "label": "Persianas",
+ "type": "section"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entity": "switch.general_luces",
+ "icon": "mdi:lightbulb",
+ "name": "Luces"
+ },
+ {
+ "entity": "switch.general_persianas",
+ "icon": "mdi:plus-circle-multiple-outline",
+ "name": "Persianas"
+ },
+ {
+ "entity": "switch.sonoffuv1",
+ "icon": "mdi:power-socket-eu",
+ "name": "Varios1"
+ },
+ {
+ "entity": "switch.sonoffuv2",
+ "icon": "mdi:power-socket-eu",
+ "name": "Varios2"
+ },
+ {
+ "entity": "switch.sonoffhumedos",
+ "icon": "mdi:power-socket-eu",
+ "name": "H\u00famedos"
+ },
+ {
+ "entity": "switch.sonoffhorno",
+ "icon": "mdi:stove",
+ "name": "Horno"
+ },
+ {
+ "entity": "switch.general_caldera",
+ "icon": "mdi:radiator",
+ "name": "Caldera"
+ },
+ {
+ "entity": "switch.sonofflavavajillas",
+ "icon": "mdi:amplifier",
+ "name": "Lavavajillas"
+ },
+ {
+ "entity": "switch.sonofflavadora",
+ "icon": "mdi:amplifier",
+ "name": "Lavavadora"
+ },
+ {
+ "entity": "switch.coche_electrico",
+ "icon": "mdi:car",
+ "name": "Coche"
+ }
+ ],
+ "head": {
+ "label": "Interruptores Generales",
+ "type": "section"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "title": "Variados",
+ "type": "entities"
+ },
+ {
+ "entity": "media_player.grupo_altavoces",
+ "type": "custom:mini-media-player"
}
],
- "show_header_toggle": false,
- "title": "Estados",
- "type": "entities"
- },
- {
- "entities": [
- "light.luz_tendedero",
- "light.luz_cocina",
- "light.luz_salon_entrada",
- "light.luz_salon_entrada_ambilight",
- "light.luz_salon_television",
- "light.luz_salon_television_ambilight",
- "light.luz_pasillo_bano",
- "light.luz_pasillo_estudio",
- "light.luz_pasillo_salon",
- "light.luz_habitacion_estudio",
- "light.luz_habitacion_principal",
- "light.luz_habitacion_mia",
- "light.luz_habitacion_noha",
- "switch.light_led_cabecero"
- ],
- "name": "Luces",
- "show_empty": false,
- "state_filter": [
- "on",
- "unavailable"
- ],
- "type": "entity-filter"
- },
- {
- "entities": [
- "binary_sensor.movimiento_pasillo_entrada",
- "binary_sensor.movimiento_cocina",
- "binary_sensor.movimiento_salon_entrada",
- "binary_sensor.movimiento_habitacion_principal",
- "binary_sensor.movimiento_habitacion_noha",
- "binary_sensor.movimiento_habitacion_mia",
- "binary_sensor.movimiento_habitacion_estudio",
- "binary_sensor.movimiento_pasillo_habitaciones"
- ],
- "name": "Movimiento",
- "show_empty": false,
- "state_filter": [
- "on"
- ],
- "type": "entity-filter"
- },
- {
- "entities": [
- {
- "entity": "binary_sensor.puerta_entrada",
- "name": "Entrada"
- },
- {
- "entity": "binary_sensor.puerta_tendedero",
- "name": "Tendedero"
- }
- ],
- "title": "Puertas",
- "type": "history-graph"
- },
- {
- "entities": [
- {
- "entity": "binary_sensor.movimiento_pasillo_entrada",
- "name": "Entrada"
- },
- {
- "entity": "binary_sensor.movimiento_cocina",
- "name": "Cocina"
- },
- {
- "entity": "binary_sensor.movimiento_salon_entrada",
- "name": "Entrada Sal\u00f3n"
- },
- {
- "entity": "binary_sensor.movimiento_habitacion_principal",
- "name": "H. Principal"
- },
- {
- "entity": "binary_sensor.movimiento_habitacion_noha",
- "name": "H. Noha"
- },
- {
- "entity": "binary_sensor.movimiento_habitacion_mia",
- "name": "H. Mia"
- },
- {
- "entity": "binary_sensor.movimiento_habitacion_estudio",
- "name": "H. Estudio"
- },
- {
- "entity": "binary_sensor.movimiento_pasillo_habitaciones",
- "name": "Pasillo H."
- }
- ],
- "hours to show": 1,
- "title": "Movimientos",
- "type": "history-graph"
- },
- {
- "entities": [
- "cover.persiana_habitacion_principal",
- "cover.persiana_habitacion_noha",
- "cover.persiana_habitacion_mia",
- "cover.persiana_habitacion_estudio",
- "cover.persiana_salon_fase_dos",
- "cover.persiana_salon_piscina"
- ],
- "name": "Persianas",
- "type": "entities"
- },
- {
- "columns": 5,
- "entities": [
- {
- "entity": "switch.general_luces",
- "icon": "mdi:lightbulb",
- "name": "Luces"
- },
- {
- "entity": "switch.general_persianas",
- "icon": "mdi:plus-circle-multiple-outline",
- "name": "Persianas"
- },
- {
- "entity": "switch.sonoffuv1",
- "icon": "mdi:power-socket-eu",
- "name": "Varios1"
- },
- {
- "entity": "switch.sonoffuv2",
- "icon": "mdi:power-socket-eu",
- "name": "Varios2"
- },
- {
- "entity": "switch.sonoffhumedos",
- "icon": "mdi:power-socket-eu",
- "name": "H\u00famedos"
- },
- {
- "entity": "switch.sonoffhorno",
- "icon": "mdi:stove",
- "name": "Horno"
- },
- {
- "entity": "switch.general_caldera",
- "icon": "mdi:radiator",
- "name": "Caldera"
- },
- {
- "entity": "switch.sonofflavavajillas",
- "icon": "mdi:amplifier",
- "name": "Lavavajillas"
- },
- {
- "entity": "switch.sonofflavadora",
- "icon": "mdi:amplifier",
- "name": "Lavavadora"
- },
- {
- "entity": "switch.coche_electrico",
- "icon": "mdi:car",
- "name": "Coche"
- }
- ],
- "show_name": true,
- "show_state": false,
- "title": "Interruptores Generales",
- "type": "glance"
- },
- {
- "entity": "media_player.musica_en_casa",
- "type": "media-control"
+ "layout": "vertical",
+ "type": "custom:layout-card"
}
],
"icon": "mdi:home",
+ "panel": true,
"path": "default_view",
"title": "Estado"
},
@@ -225,41 +482,55 @@
"badges": [],
"cards": [
{
- "entities": [
- {
- "entity": "light.luz_pasillo_salon"
+ "buttons": true,
+ "entity": "vacuum.xiaomi_vacuum_cleaner",
+ "image": "/local/lovelace/home/xiaomi_vacuum_02.jpg",
+ "labels": {
+ "battery": "Bater\u00eda",
+ "filter": "Filtro",
+ "main_brush": "Cepillo Principal",
+ "mode": "Modo",
+ "sensor": "Sensor",
+ "side_brush": "Cepillo Lateral",
+ "status": "Estado"
+ },
+ "name": "Xiaomi Vacuum",
+ "type": "custom:xiaomi-vacuum-card"
+ },
+ {
+ "card": {
+ "head": {
+ "label": "Luces",
+ "type": "section"
},
- {
- "entity": "light.luz_pasillo_estudio"
- },
- {
- "entity": "light.luz_pasillo_bano"
- }
- ],
- "type": "entities"
+ "type": "custom:fold-entity-row"
+ },
+ "filter": {
+ "include": [
+ {
+ "entity_id": "light.luz_pasillo*"
+ }
+ ]
+ },
+ "type": "custom:auto-entities"
},
{
"entities": [
{
- "entity": "vacuum.xiaomi_vacuum_cleaner"
+ "entities": [
+ {
+ "entity": "sensor.wifi_opengateway_esp32"
+ },
+ {
+ "entity": "sensor.opengateway_lora"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.openmqttgateway"
+ },
+ "type": "custom:fold-entity-row"
}
],
- "title": "Aspiradora",
- "type": "entities"
- },
- {
- "entities": [
- {
- "entity": "binary_sensor.openmqttgateway"
- },
- {
- "entity": "sensor.wifi_opengateway_esp32"
- },
- {
- "entity": "sensor.opengateway_lora"
- }
- ],
- "show_header_toggle": false,
"type": "entities"
}
],
@@ -273,57 +544,114 @@
{
"entities": [
{
- "entity": "light.luz_habitacion_principal_entrada",
- "name": "Entrada"
- },
- {
- "entity": "light.luz_habitacion_principal",
- "name": "Techo"
- },
- {
- "entity": "binary_sensor.luz_habitacion_principal_nightlight"
- },
- {
- "entity": "light.luz_cabecero_habitacion_principal",
- "name": "Cabecero"
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_principal"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_principal",
+ "name": "Movimiento",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
}
],
- "show_header_toggle": true,
- "title": "Luces",
+ "show_header_toggle": false,
"type": "entities"
},
{
"entities": [
{
- "entity": "cover.persiana_habitacion_principal"
- },
- {
- "entity": "input_boolean.control_persiana_habitacion_principal"
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_habitacion_principal_techo_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "input_boolean.luz_habitacion_principal_techo_noche",
+ "name": "Deshabilitar la luz para dormir"
+ },
+ {
+ "entity": "timer.luzhabitacionprincipal",
+ "name": "Temporizador"
+ },
+ {
+ "entity": "light.luz_habitacion_principal_entrada",
+ "name": "Luz Entrada"
+ },
+ {
+ "entity": "light.luz_habitacion_principal_cabecero",
+ "name": "Luz Cabecero"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_habitacion_principal_techo",
+ "name": "Luz Techo"
+ },
+ "type": "custom:fold-entity-row"
}
],
"show_header_toggle": false,
- "title": "Persiana ",
"type": "entities"
},
{
- "cards": [
+ "entities": [
{
"entities": [
{
- "entity": "switch.philio_technology_corporation_pan03_switch_module_with_meter_3_kw_x1_switch",
- "icon": "mdi:television",
- "name": "Televisi\u00f3n"
+ "entity": "input_boolean.control_persiana_habitacion_principal",
+ "name": "Activar el control autom\u00e1tico"
+ },
+ {
+ "entity": "timer.persianahabitacionprincipal",
+ "name": "Temporizador"
}
],
- "show_header_toggle": false,
- "type": "entities"
+ "head": {
+ "entity": "cover.persiana_habitacion_principal",
+ "name": "Persiana",
+ "type": "custom:slider-entity-row"
+ },
+ "type": "custom:fold-entity-row"
},
{
- "entity": "media_player.hab_padres",
- "type": "media-control"
+ "entity": "binary_sensor.ventana_habitacion_principal_pequena",
+ "name": "Ventana Peque\u00f1a"
+ },
+ {
+ "entity": "binary_sensor.ventana_habitacion_principal_grande",
+ "name": "Ventana Grande"
}
],
- "type": "vertical-stack"
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "artwork": "cover",
+ "entity": "media_player.hab_padres",
+ "hide": {
+ "power": true,
+ "power_state": true
+ },
+ "shortcuts": {
+ "buttons": [
+ {
+ "data": {
+ "entity_id": "switch.philio_technology_corporation_pan03_switch_module_with_meter_3_kw_x1_switch"
+ },
+ "icon": "mdi:power",
+ "id": "switch.toggle",
+ "type": "service"
+ }
+ ],
+ "columns": 4
+ },
+ "type": "custom:mini-media-player"
}
],
"icon": "mdi:home-plus",
@@ -334,55 +662,93 @@
"badges": [],
"cards": [
{
- "entities": [
+ "cards": [
{
- "entity": "binary_sensor.movimiento_habitacion_noha",
- "name": null
- }
+ "entities": [
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_noha"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_noha",
+ "name": "Movimiento",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_habitacion_noha_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "input_boolean.luz_habitacion_noha_noche",
+ "name": "Deshabilitar la luz para dormir"
+ },
+ {
+ "entity": "timer.luzhabitacionnoha",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_habitacion_noha",
+ "name": "Luz Techo"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "input_boolean.control_persiana_habitacion_noha",
+ "name": "Activar el control autom\u00e1tico"
+ },
+ {
+ "entity": "timer.persianahabitacionnoha",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "cover.persiana_habitacion_noha",
+ "name": "Persiana",
+ "type": "custom:slider-entity-row"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entity": "binary_sensor.ventana_habitacion_noha",
+ "name": "Ventana"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ "break"
],
- "hours_to_show": 1,
- "type": "history-graph"
- },
- {
- "entities": [
- {
- "entity": "light.luz_habitacion_noha",
- "name": "Luz Principal"
- },
- {
- "entity": "binary_sensor.luz_habitacion_noha_nightlight",
- "name": "Modo Noche"
- },
- {
- "entity": "input_boolean.luz_habitacion_noha_noche",
- "name": "Deshabilitar la luz para dormir"
- },
- {
- "entity": "timer.luzhabitacionnoha",
- "name": "Temporizador"
- }
- ],
- "show_header_toggle": false,
- "title": "Luces",
- "type": "entities"
- },
- {
- "entities": [
- {
- "entity": "cover.persiana_habitacion_noha",
- "name": "Persiana"
- },
- {
- "entity": "input_boolean.control_persiana_habitacion_noha",
- "name": "Activar el control autom\u00e1tico"
- }
- ],
- "show_header_toggle": false,
- "title": "Persiana",
- "type": "entities"
+ "layout": "vertical",
+ "type": "custom:layout-card"
}
],
"icon": "mdi:home-floor-1",
+ "panel": true,
"path": "habnoha",
"title": "Habitaci\u00f3n Noha"
},
@@ -392,27 +758,79 @@
{
"entities": [
{
- "entity": "light.luz_habitacion_mia"
- },
- {
- "entity": "binary_sensor.luz_habitacion_mia_nightlight"
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_mia"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_mia",
+ "name": "Movimiento",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
}
],
"show_header_toggle": false,
- "title": "Luz",
"type": "entities"
},
{
"entities": [
{
- "entity": "cover.persiana_habitacion_mia"
- },
- {
- "entity": "input_boolean.control_persiana_habitacion_mia"
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_habitacion_mia_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "input_boolean.luz_habitacion_mia_noche",
+ "name": "Deshabilitar la luz para dormir"
+ },
+ {
+ "entity": "timer.luzhabitacionmia",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_habitacion_mia",
+ "name": "Luz Techo"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "input_boolean.control_persiana_habitacion_mia",
+ "name": "Activar el control autom\u00e1tico"
+ },
+ {
+ "entity": "timer.persianahabitacionmia",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "cover.persiana_habitacion_mia",
+ "name": "Persiana",
+ "type": "custom:slider-entity-row"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entity": "binary_sensor.ventana_habitacion_mia",
+ "name": "Ventana"
}
],
"show_header_toggle": false,
- "title": "Persiana",
"type": "entities"
}
],
@@ -426,43 +844,80 @@
{
"entities": [
{
- "entity": "light.luz_habitacion_estudio"
- },
- {
- "entity": "binary_sensor.luz_habitacion_estudio_nightlight"
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_habitacion_estudio"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_habitacion_estudio",
+ "name": "Movimiento",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
}
],
"show_header_toggle": false,
- "title": "Luces",
"type": "entities"
},
{
"entities": [
{
- "entity": "cover.persiana_habitacion_estudio"
- },
- {
- "entity": "input_boolean.control_persiana_habitacion_estudio"
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_habitacion_estudio_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "input_boolean.luz_habitacion_estudio_estudiar",
+ "name": "Activar el control Autom\u00e1tico"
+ },
+ {
+ "entity": "timer.luzhabitacionestudio",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_habitacion_estudio",
+ "name": "Luz Techo"
+ },
+ "type": "custom:fold-entity-row"
}
],
"show_header_toggle": false,
- "title": "Persiana",
"type": "entities"
},
{
"entities": [
{
- "entity": "switch.xiaomi_miio_switch",
- "name": "Regleta"
+ "entities": [
+ {
+ "entity": "input_boolean.control_persiana_habitacion_estudio",
+ "name": "Activar el control autom\u00e1tico"
+ },
+ {
+ "entity": "timer.persianahabitacionestudio",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "cover.persiana_habitacion_estudio",
+ "name": "Persiana",
+ "type": "custom:slider-entity-row"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entity": "binary_sensor.ventana_habitacion_estudio",
+ "name": "Ventana"
}
],
"show_header_toggle": false,
- "title": "Enchufes",
"type": "entities"
- },
- {
- "entity": "media_player.home_salon",
- "type": "media-control"
}
],
"icon": "mdi:home-floor-3",
@@ -473,164 +928,270 @@
"badges": [],
"cards": [
{
- "entities": [
+ "cards": [
{
- "entity": "sensor.wireless_router_archer_c7_kbyte_sec_received",
- "name": "kbytes/sec recibidos"
+ "entities": [
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_salon_entrada"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_salon_entrada",
+ "name": "Movimiento Entrada",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_salon_television"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_salon_television",
+ "name": "Movimiento Televisi\u00f3n",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
},
{
- "entity": "sensor.wireless_router_archer_c7_kbyte_sec_sent",
- "name": "kbytes/sec enviados"
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_salon_entrada_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "light.luz_salon_entrada_ambilight",
+ "name": "Luz de Ambiente"
+ },
+ {
+ "entity": "timer.luzsalonentrada",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_salon_entrada",
+ "name": "Luz Entrada"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_salon_television_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "light.luz_salon_television_ambilight",
+ "name": "Luz de Ambiente"
+ },
+ {
+ "entity": "timer.luzsalontelevision",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_salon_television",
+ "name": "Luz Televisi\u00f3n"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "input_boolean.control_persiana_salon_fase_dos",
+ "name": "Activar el control autom\u00e1tico"
+ },
+ {
+ "entity": "timer.persianafasedos",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "cover.persiana_salon_fase_dos",
+ "name": "Persiana Fase Dos",
+ "type": "custom:slider-entity-row"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entity": "binary_sensor.ventana_salon_fase_dos_grande",
+ "name": "Ventana Fase Dos Grande"
+ },
+ {
+ "entity": "binary_sensor.ventana_salon_fase_dos_pequena",
+ "name": "Ventana Fase Dos Peque\u00f1a"
+ },
+ {
+ "entities": [
+ {
+ "entity": "input_boolean.control_persiana_salon_piscina",
+ "name": "Activar el control autom\u00e1tico"
+ },
+ {
+ "entity": "timer.persianapiscina",
+ "name": "Temporizador"
+ }
+ ],
+ "head": {
+ "entity": "cover.persiana_salon_piscina",
+ "name": "Persiana Fase Dos",
+ "type": "custom:slider-entity-row"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entity": "binary_sensor.ventana_salon_piscina_grande",
+ "name": "Ventana Piscina Grande"
+ },
+ {
+ "entity": "binary_sensor.ventana_salon_piscina_pequena",
+ "name": "Ventana Piscina Peque\u00f1a"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ "break",
+ {
+ "columns": 3,
+ "entities": [
+ {
+ "entity": "script.apagar_encender_humidificador",
+ "icon": "mdi:power",
+ "name": "ON/OFF"
+ },
+ {
+ "entity": "script.mas_humidificador",
+ "icon": "mdi:plus",
+ "name": "M\u00e1s"
+ },
+ {
+ "entity": "script.menos_humidificador",
+ "icon": "mdi:minus",
+ "name": "Menos"
+ },
+ {
+ "entity": "script.display_humidificador",
+ "icon": "mdi:television",
+ "name": "Display"
+ },
+ {
+ "entity": "script.calentador_humidificador",
+ "icon": "mdi:radiator",
+ "name": "Calentador"
+ },
+ {
+ "entity": "script.luz_humidificador",
+ "icon": "mdi:lightbulb-outline",
+ "name": "Luz"
+ },
+ {
+ "entity": "script.control_humedad_humidificador",
+ "icon": "mdi:cloud-outline",
+ "name": "Humedad"
+ },
+ {
+ "entity": "script.tiempo_humidificador",
+ "icon": "mdi:clock",
+ "name": "Tiempo"
+ },
+ {
+ "entity": "script.niebla_humidificador",
+ "icon": "mdi:shower-head",
+ "name": "Fuerza Niebla"
+ }
+ ],
+ "show_state": false,
+ "title": "Humidificador",
+ "type": "glance"
+ },
+ {
+ "entity": "plant.salon",
+ "name": "Plantas del sal\u00f3n",
+ "type": "plant-status"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "switch.greenwave_reality_inc_powernode_6_port_switch_5",
+ "name": "Purificador de Aire",
+ "primary": {
+ "entity": "sensor.greenwave_reality_inc_powernode_6_port_power_5",
+ "name": "Consumo"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ },
+ {
+ "entity": "switch.greenwave_reality_inc_powernode_6_port_switch_6",
+ "name": "Purificador de Aire",
+ "primary": {
+ "entity": "sensor.greenwave_reality_inc_powernode_6_port_power_6",
+ "name": "Consumo"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ },
+ {
+ "entity": "switch.xiaomi_strip_2",
+ "name": "Regleta Principal Mueble"
+ }
+ ],
+ "head": {
+ "label": "Interruptores",
+ "type": "section"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entity": "media_player.television_salon",
+ "type": "custom:mini-media-player"
+ },
+ {
+ "entity": "media_player.google_cast",
+ "type": "custom:mini-media-player"
+ }
+ ],
+ "type": "entities"
}
],
- "hours_to_show": 2,
- "refresh_interval": 60,
- "title": "Gr\u00e1fica de Transferencia (2 horas)",
- "type": "history-graph"
- },
- {
- "entities": [
- {
- "entity": "light.luz_salon_entrada"
- },
- {
- "entity": "light.luz_salon_entrada_ambilight"
- },
- {
- "entity": "binary_sensor.luz_salon_entrada_nightlight"
- },
- {
- "entity": "light.luz_salon_television"
- },
- {
- "entity": "light.luz_salon_television_ambilight"
- },
- {
- "entity": "binary_sensor.luz_salon_television_nightlight"
- }
- ],
- "title": "Luces",
- "type": "entities"
- },
- {
- "entities": [
- {
- "entity": "cover.persiana_salon_fase_dos"
- },
- {
- "entity": "input_boolean.control_persiana_salon_fase_dos"
- },
- {
- "entity": "cover.persiana_salon_piscina"
- },
- {
- "entity": "input_boolean.control_persiana_salon_piscina"
- }
- ],
- "show_header_toggle": false,
- "title": "Persianas",
- "type": "entities"
- },
- {
- "entity": "media_player.television_salon",
- "type": "media-control"
- },
- {
- "entity": "media_player.google_cast",
- "type": "media-control"
- },
- {
- "columns": 3,
- "entities": [
- {
- "entity": "script.apagar_encender_humidificador",
- "icon": "mdi:power",
- "name": "ON/OFF"
- },
- {
- "entity": "script.mas_humidificador",
- "icon": "mdi:plus",
- "name": "M\u00e1s"
- },
- {
- "entity": "script.menos_humidificador",
- "icon": "mdi:minus",
- "name": "Menos"
- },
- {
- "entity": "script.display_humidificador",
- "icon": "mdi:television",
- "name": "Display"
- },
- {
- "entity": "script.calentador_humidificador",
- "icon": "mdi:radiator",
- "name": "Calentador"
- },
- {
- "entity": "script.luz_humidificador",
- "icon": "mdi:lightbulb-outline",
- "name": "Luz"
- },
- {
- "entity": "script.control_humedad_humidificador",
- "icon": "mdi:cloud-outline",
- "name": "Humedad"
- },
- {
- "entity": "script.tiempo_humidificador",
- "icon": "mdi:clock",
- "name": "Tiempo"
- },
- {
- "entity": "script.niebla_humidificador",
- "icon": "mdi:shower-head",
- "name": "Fuerza Niebla"
- }
- ],
- "show_state": false,
- "title": "Humidificador",
- "type": "glance"
- },
- {
- "entity": "fan.xiaomi_miio_device_2",
- "hold_action": {
- "action": "toggle"
- },
- "name": "Purificador de Aire",
- "tap_action": {
- "action": "more-info"
- },
- "type": "entity-button"
- },
- {
- "entity": "plant.salon",
- "name": "Plantas del sal\u00f3n",
- "type": "plant-status"
- },
- {
- "entities": [
- {
- "entity": "switch.xiaomi_strip_2",
- "name": "Regleta Principal Mueble"
- }
- ],
- "show_header_toggle": false,
- "title": "Interruptores",
- "type": "entities"
- },
- {
- "entities": [
- "sensor.temperatura_salon",
- "sensor.temperatura_exterior"
- ],
- "hours_to_show": 96,
- "refresh_interval": 300,
- "title": "Temperaturas",
- "type": "history-graph"
+ "layout": "vertical",
+ "type": "custom:layout-card"
}
],
"icon": "mdi:sofa",
+ "panel": true,
"path": "salon",
"title": "Sal\u00f3n"
},
@@ -640,59 +1201,91 @@
{
"entities": [
{
- "entity": "binary_sensor.popp_smoke_detector_and_siren_sensor",
- "name": "Estado"
- },
- {
- "entity": "switch.popp_smoke_detector_and_siren_switch",
- "icon": "mdi:surround-sound",
- "name": "Activar"
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_cocina"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_cocina",
+ "name": "Movimiento",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
}
],
"show_header_toggle": false,
- "title": "Alarma de Humos",
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entities": [
+ {
+ "entity": "binary_sensor.luz_cocina_nightlight",
+ "name": "Modo Noche"
+ },
+ {
+ "entity": "timer.luzcocina",
+ "name": "Temporizador"
+ },
+ {
+ "entity": "light.led_cocina",
+ "name": "Led Cocina"
+ },
+ {
+ "entity": "light.luz_tendedero",
+ "name": "Luz Tendedero"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_cocina",
+ "name": "Luz Techo"
+ },
+ "type": "custom:fold-entity-row"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "entities": [
+ {
+ "entity": "switch.popp_smoke_detector_and_siren_switch",
+ "icon": "mdi:surround-sound",
+ "name": "Alarma de Humos",
+ "primary": {
+ "entity": "binary_sensor.popp_smoke_detector_and_siren_sensor",
+ "name": "Estado"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ },
+ {
+ "entity": "switch.everspring_an158_plug_in_meter_appliance_module_switch",
+ "icon": "mdi:weather-windy",
+ "name": "Campana Extractora",
+ "primary": {
+ "entity": "sensor.everspring_an158_plug_in_meter_appliance_module_power",
+ "name": "Actual"
+ },
+ "secondary": {
+ "entity": "sensor.everspring_an158_plug_in_meter_appliance_module_energy",
+ "name": "Acumulado"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ }
+ ],
"type": "entities"
},
{
"entity": "media_player.home_cocina",
- "type": "media-control"
- },
- {
- "entities": [
- {
- "entity": "light.luz_cocina"
- },
- {
- "entity": "binary_sensor.luz_cocina_nightlight"
- },
- {
- "entity": "light.led_cocina"
- },
- {
- "entity": "light.luz_tendedero"
- }
- ],
- "show_header_toggle": false,
- "title": "Luces",
- "type": "entities"
- },
- {
- "entities": [
- {
- "entity": "switch.everspring_an158_plug_in_meter_appliance_module_switch",
- "name": "Campana Extractora"
- },
- {
- "entity": "sensor.everspring_an158_plug_in_meter_appliance_module_power",
- "name": "Consumo Campana Extractora Actual"
- },
- {
- "entity": "sensor.everspring_an158_plug_in_meter_appliance_module_energy",
- "name": "Consumo Campana Extractora Acumulado"
- }
- ],
- "title": "Interruptores",
- "type": "entities"
+ "type": "custom:mini-media-player"
}
],
"icon": "mdi:food-variant",
@@ -706,47 +1299,56 @@
{
"entities": [
{
- "entity": "binary_sensor.movimiento_bano_general"
+ "entities": [
+ {
+ "entities": [
+ "binary_sensor.movimiento_bano_general"
+ ],
+ "hours_to_show": 1,
+ "type": "custom:hui-history-graph-card"
+ }
+ ],
+ "head": {
+ "entity": "binary_sensor.movimiento_bano_general",
+ "name": "Movimiento Ba\u00f1o General",
+ "secondary_info": "last-changed"
+ },
+ "type": "custom:fold-entity-row"
}
],
"show_header_toggle": false,
- "title": "Movimiento Ba\u00f1o General",
"type": "entities"
},
{
"entities": [
{
- "entity": "sensor.sonoffbanogeneral_status",
- "name": "Estado Interruptores"
+ "entities": [
+ {
+ "entity": "light.luz_bano_general_secundaria",
+ "name": "Luz Secundaria"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_bano_general_principal",
+ "name": "Luz Ba\u00f1o General"
+ },
+ "type": "custom:fold-entity-row"
},
{
- "entity": "light.luz_bano_general_principal",
- "name": "Luz Principal"
- },
- {
- "entity": "light.luz_bano_general_secundaria",
- "name": "Luz Secundaria"
+ "entities": [
+ {
+ "entity": "light.luz_bano_principal_secundaria",
+ "name": "Luz Secundaria"
+ }
+ ],
+ "head": {
+ "entity": "light.luz_bano_principal_principal",
+ "name": "Luz Ba\u00f1o Principal"
+ },
+ "type": "custom:fold-entity-row"
}
],
- "title": "Luces Ba\u00f1o General",
- "type": "entities"
- },
- {
- "entities": [
- {
- "entity": "sensor.sonoffbanoprincipal_status",
- "name": "Estado Interruptores"
- },
- {
- "entity": "light.luz_bano_principal_principal",
- "name": "Luz Principal"
- },
- {
- "entity": "light.luz_bano_principal_secundaria",
- "name": "Luz Secundaria"
- }
- ],
- "title": "Ba\u00f1o Principal",
+ "show_header_toggle": false,
"type": "entities"
}
],
@@ -754,6 +1356,106 @@
"path": "banos",
"title": "Ba\u00f1os"
},
+ {
+ "badges": [],
+ "cards": [
+ {
+ "entities": [
+ {
+ "entity": "sensor.refresh_xee",
+ "icon": "mdi:cookie",
+ "name": "Estado token XEE"
+ }
+ ],
+ "show_header_toggle": false,
+ "type": "entities"
+ },
+ {
+ "cards": [
+ {
+ "entities": [
+ {
+ "entity": "sensor.citroen_fecha_update",
+ "name": "Hora de Actualizaci\u00f3n"
+ },
+ {
+ "entity": "sensor.citroen_combustible",
+ "name": "Gasolina"
+ },
+ {
+ "entity": "sensor.citroen_bateria",
+ "name": "Bater\u00eda"
+ },
+ {
+ "entity": "sensor.citroen_velocidad",
+ "name": "Velocidad"
+ },
+ {
+ "entity": "sensor.citroen_kilometros",
+ "name": "Kil\u00f3metros"
+ },
+ {
+ "entity": "sensor.citroen_revoluciones",
+ "name": "Revoluciones por Minuto"
+ }
+ ],
+ "show_header_toggle": false,
+ "title": "Citroen 2220HVZ",
+ "type": "entities"
+ },
+ {
+ "camera_image": "camera.posicion_citroen",
+ "entities": [],
+ "title": "Posici\u00f3n del Citroen",
+ "type": "picture-glance"
+ }
+ ],
+ "type": "vertical-stack"
+ },
+ {
+ "cards": [
+ {
+ "entities": [
+ {
+ "entity": "sensor.smart_fecha_update",
+ "name": "Hora de Actualizaci\u00f3n"
+ },
+ {
+ "entity": "sensor.smart_bateria",
+ "name": "Bater\u00eda"
+ },
+ {
+ "entity": "sensor.smart_velocidad",
+ "name": "Velocidad"
+ },
+ {
+ "entity": "sensor.smart_kilometros",
+ "name": "Kil\u00f3metros"
+ },
+ {
+ "entity": "sensor.smart_revoluciones",
+ "name": "Revoluciones por Minuto"
+ }
+ ],
+ "show_header_toggle": false,
+ "title": "Smart 8343 GMF",
+ "type": "entities"
+ },
+ {
+ "camera_image": "camera.posicion_smart",
+ "entities": [],
+ "title": "Posici\u00f3n del Smart",
+ "type": "picture-glance"
+ }
+ ],
+ "type": "vertical-stack"
+ }
+ ],
+ "icon": "mdi:car",
+ "panel": false,
+ "path": "vehiculos",
+ "title": "Vehiculos"
+ },
{
"badges": [],
"cards": [
@@ -1047,110 +1749,10 @@
"path": "consumos",
"title": "Consumos"
},
- {
- "badges": [],
- "cards": [
- {
- "entities": [
- {
- "entity": "sensor.refresh_xee",
- "icon": "mdi:cookie",
- "name": "Estado token XEE"
- }
- ],
- "show_header_toggle": false,
- "type": "entities"
- },
- {
- "cards": [
- {
- "entities": [
- {
- "entity": "sensor.citroen_fecha_update",
- "name": "Hora de Actualizaci\u00f3n"
- },
- {
- "entity": "sensor.citroen_combustible",
- "name": "Gasolina"
- },
- {
- "entity": "sensor.citroen_bateria",
- "name": "Bater\u00eda"
- },
- {
- "entity": "sensor.citroen_velocidad",
- "name": "Velocidad"
- },
- {
- "entity": "sensor.citroen_kilometros",
- "name": "Kil\u00f3metros"
- },
- {
- "entity": "sensor.citroen_revoluciones",
- "name": "Revoluciones por Minuto"
- }
- ],
- "show_header_toggle": false,
- "title": "Citroen 2220HVZ",
- "type": "entities"
- },
- {
- "camera_image": "camera.posicion_citroen",
- "entities": [],
- "title": "Posici\u00f3n del Citroen",
- "type": "picture-glance"
- }
- ],
- "type": "vertical-stack"
- },
- {
- "cards": [
- {
- "entities": [
- {
- "entity": "sensor.smart_fecha_update",
- "name": "Hora de Actualizaci\u00f3n"
- },
- {
- "entity": "sensor.smart_bateria",
- "name": "Bater\u00eda"
- },
- {
- "entity": "sensor.smart_velocidad",
- "name": "Velocidad"
- },
- {
- "entity": "sensor.smart_kilometros",
- "name": "Kil\u00f3metros"
- },
- {
- "entity": "sensor.smart_revoluciones",
- "name": "Revoluciones por Minuto"
- }
- ],
- "show_header_toggle": false,
- "title": "Smart 8343 GMF",
- "type": "entities"
- },
- {
- "camera_image": "camera.posicion_smart",
- "entities": [],
- "title": "Posici\u00f3n del Smart",
- "type": "picture-glance"
- }
- ],
- "type": "vertical-stack"
- }
- ],
- "icon": "mdi:car",
- "panel": false,
- "path": "vehiculos",
- "title": "Vehiculos"
- },
{
"badges": [
- "binary_sensor.workday",
- "binary_sensor.vacaciones",
+ "binary_sensor.trabajo",
+ "binary_sensor.colegio",
"sun.sun",
"sensor.db_size",
"sensor.coste_ayer_tdh",
@@ -1662,6 +2264,47 @@
"on"
],
"type": "entity-filter"
+ },
+ {
+ "entities": [
+ {
+ "entity": "switch.greenwave_reality_inc_powernode_6_port_switch_5",
+ "name": "Purificador de Aire",
+ "primary": {
+ "entity": "sensor.greenwave_reality_inc_powernode_6_port_power_5",
+ "name": "Consumo"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ },
+ {
+ "entity": "switch.greenwave_reality_inc_powernode_6_port_switch_6",
+ "name": "Humidificador",
+ "primary": {
+ "entity": "sensor.greenwave_reality_inc_powernode_6_port_power_6",
+ "name": "Consumo"
+ },
+ "toggle": true,
+ "type": "custom:multiple-entity-row"
+ },
+ {
+ "entity": "switch.xiaomi_strip_2",
+ "name": "Regleta Principal Mueble"
+ }
+ ],
+ "head": {
+ "label": "Interruptores",
+ "type": "section"
+ },
+ "type": "custom:fold-entity-row"
+ },
+ {
+ "entities": [
+ "sensor.greenwave_reality_inc_powernode_6_port_power_5",
+ "sensor.greenwave_reality_inc_powernode_6_port_power_6"
+ ],
+ "hours to show": 96,
+ "type": "history-graph"
}
],
"icon": "mdi:alert-decagram",
diff --git a/www/community/entity-attributes-card/entity-attributes-card.js b/www/community/entity-attributes-card/entity-attributes-card.js
new file mode 100644
index 0000000..30a30ca
--- /dev/null
+++ b/www/community/entity-attributes-card/entity-attributes-card.js
@@ -0,0 +1,125 @@
+class EntityAttributesCard extends HTMLElement {
+ constructor() {
+ super();
+ this.attachShadow({ mode: 'open' });
+ }
+
+ _getAttributes(hass, filters) {
+ function _filterName(stateObj, pattern) {
+ let parts;
+ let attr_id;
+ let attribute;
+ if (typeof (pattern) === "object") {
+ parts = pattern["key"].split(".");
+ attribute = pattern["key"];
+
+ } else {
+ parts = pattern.split(".");
+ attribute = pattern;
+ }
+ attr_id = parts[2];
+ if (attr_id.indexOf('*') === -1) {
+ return stateObj == attribute;
+ }
+ const regEx = new RegExp(`^${attribute.replace(/\*/g, '.*')}$`, 'i');
+ return stateObj.search(regEx) === 0;
+ }
+ const attributes = new Map();
+ filters.forEach((filter) => {
+ const filters = [];
+ filters.push(stateObj => _filterName(stateObj, filter));
+ Object.keys(hass.states).sort().forEach(key => {
+ Object.keys(hass.states[key].attributes).sort().forEach(attr_key => {
+ if (filters.every(filterFunc => filterFunc(`${key}.${attr_key}`))) {
+ attributes.set(`${key}.${attr_key}`, {
+ name: `${filter.name?filter.name:attr_key.replace(/_/g, ' ')}`,
+ value: `${hass.states[key].attributes[attr_key]} ${filter.unit||''}`.trim(),
+ });
+ }
+ });
+ });
+ });
+ return Array.from(attributes.values());
+ }
+
+ setConfig(config) {
+ if (!config.filter.include || !Array.isArray(config.filter.include)) {
+ throw new Error('Please define filters');
+ }
+
+ if (!config.heading_name) config.heading_name = 'Attributes';
+ if (!config.heading_state) config.heading_state = 'States';
+
+ const root = this.shadowRoot;
+ if (root.lastChild) root.removeChild(root.lastChild);
+
+ const cardConfig = Object.assign({}, config);
+ const card = document.createElement('ha-card');
+ card.header = config.title;
+ const content = document.createElement('div');
+ const style = document.createElement('style');
+ style.textContent = `
+ table {
+ width: 100%;
+ padding: 16px;
+ }
+ thead th {
+ text-align: left;
+ }
+ tbody tr:nth-child(odd) {
+ background-color: var(--paper-card-background-color);
+ }
+ tbody tr:nth-child(even) {
+ background-color: var(--secondary-background-color);
+ }
+ `;
+ content.innerHTML = `
+
+
+
+ | ${config.heading_name} |
+ ${config.heading_state} |
+
+
+
+
+
+ `;
+ card.appendChild(style);
+ card.appendChild(content);
+ root.appendChild(card)
+ this._config = cardConfig;
+ }
+
+ _updateContent(element, attributes) {
+ element.innerHTML = `
+
+ ${attributes.map((attribute) => `
+
+ | ${attribute.name} |
+ ${attribute.value} |
+
+ `).join('')}
+ `;
+ }
+
+ set hass(hass) {
+ const config = this._config;
+ const root = this.shadowRoot;
+
+ let attributes = this._getAttributes(hass, config.filter.include);
+ if (config.filter.exclude) {
+ const excludeAttributes = this._getAttributes(hass, config.filter.exclude).map(attr => attr.name);
+ attributes = attributes.filter(attr => {
+ return !excludeAttributes.includes(attr.name)
+ });
+ }
+ this._updateContent(root.getElementById('attributes'), attributes);
+ }
+
+ getCardSize() {
+ return 1;
+ }
+}
+
+customElements.define('entity-attributes-card', EntityAttributesCard);
diff --git a/www/community/entity-attributes-card/entity-attributes-card.js.gz b/www/community/entity-attributes-card/entity-attributes-card.js.gz
new file mode 100644
index 0000000..3ee340d
Binary files /dev/null and b/www/community/entity-attributes-card/entity-attributes-card.js.gz differ
diff --git a/www/community/lovelace-auto-entities/auto-entities.js b/www/community/lovelace-auto-entities/auto-entities.js
new file mode 100644
index 0000000..179c9a6
--- /dev/null
+++ b/www/community/lovelace-auto-entities/auto-entities.js
@@ -0,0 +1,225 @@
+customElements.whenDefined('card-tools').then(() => {
+class AutoEntities extends cardTools.LitElement {
+
+ setConfig(config) {
+ if(!config || !config.card)
+ throw new Error("Invalid configuration");
+
+ this._config = config;
+ this.data = {};
+
+ this.entities = this.get_entities() || [];
+ this.card = cardTools.createCard(Object.assign({entities: this.entities}, config.card));
+ }
+
+
+ match(pattern, str){
+ if (typeof(str) === "string" && typeof(pattern) === "string") {
+ if((pattern.startsWith('/') && pattern.endsWith('/')) || pattern.indexOf('*') !== -1) {
+ if(pattern[0] !== '/') {
+ pattern = pattern.replace(/\./g, '\.');
+ pattern = pattern.replace(/\*/g, '.*');
+ pattern = `/^${pattern}$/`;
+ }
+ var regex = new RegExp(pattern.substr(1).slice(0,-1));
+ return regex.test(str);
+ }
+ }
+ if(typeof(pattern) === "string") {
+ if(pattern.indexOf(":") !== -1 && typeof(str) === "object") {
+ while(pattern.indexOf(":") !== -1)
+ {
+ str = str[pattern.split(":")[0]];
+ pattern = pattern.substr(pattern.indexOf(":")+1, pattern.length);
+ }
+ }
+ if(pattern.startsWith("<=")) return parseFloat(str) <= parseFloat(pattern.substr(2));
+ if(pattern.startsWith(">=")) return parseFloat(str) >= parseFloat(pattern.substr(2));
+ if(pattern.startsWith("<")) return parseFloat(str) < parseFloat(pattern.substr(1));
+ if(pattern.startsWith(">")) return parseFloat(str) > parseFloat(pattern.substr(1));
+ if(pattern.startsWith("!")) return parseFloat(str) != parseFloat(pattern.substr(1));
+ if(pattern.startsWith("=")) return parseFloat(str) == parseFloat(pattern.substr(1));
+ }
+ return str === pattern;
+ }
+
+ match_filter(hass, entities, filter) {
+ let retval = [];
+ let count = -1;
+ entities.forEach((i) => {
+ count++;
+ if(!hass.states) return;
+ const e = (typeof(i) === "string")?hass.states[i]:hass.states[i.entity];
+ if(!e) return;
+
+ let unmatched = false;
+ Object.keys(filter).forEach((filterKey) => {
+ const key = filterKey.split(" ")[0];
+ const value = filter[filterKey];
+ switch(key) {
+ case "options":
+ break;
+ case "domain":
+ if(!this.match(value, e.entity_id.split('.')[0]))
+ unmatched = true;
+ break;
+ case "state":
+ if(!this.match(value, e.state))
+ unmatched = true;
+ break;
+ case "entity_id":
+ if(!this.match(value, e.entity_id))
+ unmatched = true;
+ break;
+ case "name":
+ if(!e.attributes.friendly_name
+ || !this.match(value, e.attributes.friendly_name)
+ )
+ unmatched = true;
+ break;
+ case "area":
+ let found = false;
+ this.data.areas.forEach((a) => {
+ if(found) return;
+ if(this.match(value, a.name)) {
+ this.data.devices.forEach((d) => {
+ if(found) return;
+ if(d.area_id && d.area_id === a.area_id) {
+ this.data.entities.forEach((en) => {
+ if(found) return;
+ if(en.device_id === d.id && en.entity_id === e.entity_id) {
+ found = true;
+ }
+ });
+ }
+ });
+ }
+ });
+ if(!found) unmatched = true;
+ break;
+ case "group":
+ if(!value.startsWith("group.")
+ || !hass.states[value]
+ || !hass.states[value].attributes.entity_id
+ || !hass.states[value].attributes.entity_id.includes(e.entity_id)
+ )
+ unmatched = true;
+ break;
+ case "attributes":
+ Object.keys(value).forEach((entityKey) => {
+ const k = entityKey.split(" ")[0];
+ const v = value[entityKey];
+ if(!e.attributes[k]
+ || !this.match(v, e.attributes[k])
+ )
+ unmatched = true;
+ });
+ break;
+ default:
+ unmatched = true;
+ }
+ });
+ if(!unmatched) retval.push(count);
+ });
+ return retval;
+ }
+
+ get_entities()
+ {
+ let entities = [];
+ if(this._config.entities)
+ this._config.entities.forEach((e) => entities.push(e));
+
+ if(this._hass && this._config.filter) {
+
+ if(this._config.filter.include){
+ this._config.filter.include.forEach((f) => {
+ const add = this.match_filter(this._hass, Object.keys(this._hass.states), f);
+ let toAdd = [];
+ add.forEach((i) => {
+ toAdd.push(Object.assign({entity: Object.keys(this._hass.states)[i]}, f.options));
+ });
+ toAdd.sort((a,b) => {
+ if (a.entity < b.entity) return -1;
+ if (a.entity > b.entity) return 1;
+ return 0;
+ });
+ toAdd.forEach((i) => entities.push(i));
+ });
+ }
+
+ if(this._config.filter.exclude) {
+ this._config.filter.exclude.forEach((f) => {
+ const remove = this.match_filter(this._hass, entities, f);
+ for(var i = remove.length-1; i >= 0; i--)
+ {
+ entities.splice(remove[i],1);
+ }
+ });
+ }
+ }
+ return entities;
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+ render() {
+ if(this.entities.length === 0 && this._config.show_empty === false)
+ return cardTools.LitHtml``;
+ return cardTools.LitHtml`
+ ${this.card}
+ `;
+ }
+
+ async get_data(hass) {
+ try {
+ this.data.areas = await hass.callWS({type: "config/area_registry/list"});
+ this.data.devices = await hass.callWS({type: "config/device_registry/list"});
+ this.data.entities = await hass.callWS({type: "config/entity_registry/list"});
+ } catch (err) {
+ }
+ }
+
+ _compare_arrays(a,b) {
+ if(a === b) return true;
+ if(a == null || b == null) return false;
+ if(a.length != b.length) return false;
+ for(var i = 0; i < a.length; i++) {
+ if(a[i] !== b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ set hass(hass) {
+ this._hass = hass;
+ this.get_data(hass).then(() => {
+ if(this.card)
+ {
+ this.card.hass = this._hass;
+ }
+
+ const oldEntities = this.entities.map((e) => e.entity);
+ this.entities = this.get_entities() || [];
+ const newEntities = this.entities.map((e) => e.entity);
+
+ if(!this._compare_arrays(oldEntities, newEntities)) {
+ this.card.setConfig(Object.assign({entities: this.entities}, this._config.card));
+ this.requestUpdate();
+ }
+ });
+ }
+
+}
+
+customElements.define('auto-entities', AutoEntities);
+});
+
+window.setTimeout(() => {
+ if(customElements.get('card-tools')) return;
+ customElements.define('auto-entities', class extends HTMLElement{
+ setConfig() { throw new Error("Can't find card-tools. See https://github.com/thomasloven/lovelace-card-tools");}
+ });
+}, 2000);
diff --git a/www/community/lovelace-auto-entities/auto-entities.js.gz b/www/community/lovelace-auto-entities/auto-entities.js.gz
new file mode 100644
index 0000000..129f15c
Binary files /dev/null and b/www/community/lovelace-auto-entities/auto-entities.js.gz differ
diff --git a/www/community/lovelace-card-tools/card-tools.js b/www/community/lovelace-card-tools/card-tools.js
new file mode 100644
index 0000000..364522c
--- /dev/null
+++ b/www/community/lovelace-card-tools/card-tools.js
@@ -0,0 +1,428 @@
+customElements.define('card-tools',
+class {
+ static get CUSTOM_TYPE_PREFIX() { return "custom:"}
+ static get version() { return "0.4"}
+
+ static checkVersion(v) {
+ if (this.version < v) {
+ throw new Error(`Old version of card-tools found. Get the latest version of card-tools.js from https://github.com/thomasloven/lovelace-card-tools`);
+ }
+ }
+
+ static deprecationWarning() {
+ if(window.cardTools_deprecationWarning) return;
+ console.warn("One or more of your lovelace plugins are using the functions cardTools.litElement(), cardTools.litHtml() or cardTools.hass(). Those are replaced with better alternatives and will be removed a some point in the future.")
+ console.warn("If you are a plugin developer, make sure you are using the new functions (see documentation).");
+ console.warn("If you are a plugin user, feel free to ignore this warning (or poke the developer of your plugins - not me though, I already know about this).")
+ console.warn("Best regards / thomasloven - " + (document.currentScript && document.currentScript.src));
+ window.cardTools_deprecationWarning = true;
+ }
+
+ static get LitElement() {
+ if(customElements.get('home-assistant-main'))
+ return Object.getPrototypeOf(customElements.get('home-assistant-main'));
+ return Object.getPrototypeOf(customElements.get('hui-view'));
+ }
+ static litElement() { // Backwards compatibility - deprecated
+ this.deprecationWarning();
+ return this.LitElement;
+ }
+
+ static get LitHtml() {
+ return this.LitElement.prototype.html;
+ }
+ static litHtml() { // Backwards compatibility - deprecated
+ this.deprecationWarning();
+ return this.LitHtml;
+ }
+
+ static get LitCSS() {
+ return this.LitElement.prototype.css;
+ }
+
+ static get hass() {
+ var hass = function() { // Backwards compatibility - deprecated
+ this.deprecationWarning();
+ return hass;
+ }
+ for (var k in document.querySelector('home-assistant').hass)
+ hass[k] = document.querySelector('home-assistant').hass[k];
+ hass.original = document.querySelector('home-assistant').hass;
+ return hass;
+ }
+
+ static fireEvent(ev, detail, entity=null) {
+ ev = new Event(ev, {
+ bubbles: true,
+ cancelable: false,
+ composed: true,
+ });
+ ev.detail = detail || {};
+ if(entity) {
+ entity.dispatchEvent(ev);
+ } else {
+ var root = document.querySelector("home-assistant");
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("home-assistant-main");
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("app-drawer-layout partial-panel-resolver");
+ root = root && root.shadowRoot || root;
+ root = root && root.querySelector("ha-panel-lovelace");
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("hui-root");
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("ha-app-layout #view");
+ root = root && root.firstElementChild;
+ if (root) root.dispatchEvent(ev);
+ }
+ }
+
+ static get lovelace() {
+ var root = document.querySelector("home-assistant");
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("home-assistant-main");
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("app-drawer-layout partial-panel-resolver");
+ root = root && root.shadowRoot || root;
+ root = root && root.querySelector("ha-panel-lovelace")
+ root = root && root.shadowRoot;
+ root = root && root.querySelector("hui-root")
+ if (root) {
+ var ll = root.lovelace
+ ll.current_view = root.___curView;
+ return ll;
+ }
+ return null;
+ }
+
+ static createThing(thing, config) {
+ const _createThing = (tag, config) => {
+ const element = document.createElement(tag);
+ try {
+ element.setConfig(config);
+ } catch (err) {
+ console.error(tag, err);
+ return _createError(err.message, config);
+ }
+ return element;
+ };
+
+ const _createError = (error, config) => {
+ return _createThing("hui-error-card", {
+ type: "error",
+ error,
+ config,
+ });
+ };
+
+ if(!config || typeof config !== "object" || !config.type)
+ return _createError(`No ${thing} type configured`, config);
+ let tag = config.type;
+ if(config.error) {
+ const err = config.error;
+ delete config.error;
+ return _createError(err, config);
+ }
+ if(tag.startsWith(this.CUSTOM_TYPE_PREFIX))
+ tag = tag.substr(this.CUSTOM_TYPE_PREFIX.length);
+ else
+ tag = `hui-${tag}-${thing}`;
+
+ if(customElements.get(tag))
+ return _createThing(tag, config);
+
+ // If element doesn't exist (yet) create an error
+ const element = _createError(
+ `Custom element doesn't exist: ${tag}.`,
+ config
+ );
+ element.style.display = "None";
+ const timer = setTimeout(() => {
+ element.style.display = "";
+ }, 2000);
+ // Remove error if element is defined later
+ customElements.whenDefined(tag).then(() => {
+ clearTimeout(timer);
+ this.fireEvent("ll-rebuild", {}, element);
+ });
+
+ return element;
+ }
+
+ static createCard(config) {
+ return this.createThing("card", config);
+ }
+
+ static createElement(config) {
+ return this.createThing("element", config);
+ }
+
+ static createEntityRow(config) {
+ const SPECIAL_TYPES = new Set([
+ "call-service",
+ "divider",
+ "section",
+ "weblink",
+ ]);
+ const DEFAULT_ROWS = {
+ alert: "toggle",
+ automation: "toggle",
+ climate: "climate",
+ cover: "cover",
+ fan: "toggle",
+ group: "group",
+ input_boolean: "toggle",
+ input_number: "input-number",
+ input_select: "input-select",
+ input_text: "input-text",
+ light: "toggle",
+ media_player: "media-player",
+ lock: "lock",
+ remote: "toggle",
+ scene: "scene",
+ script: "script",
+ sensor: "sensor",
+ timer: "timer",
+ switch: "toggle",
+ vacuum: "toggle",
+ water_heater: "climate",
+ input_datetime: "input-datetime",
+ };
+
+ if(!config || typeof config !== "object" || (!config.entity && !config.type)) {
+ Object.assign(config, {error: "Invalid config given"});
+ return this.createThing("", config);
+ }
+
+ const type = config.type || "default";
+ if(SPECIAL_TYPES.has(type) || type.startsWith(this.CUSTOM_TYPE_PREFIX))
+ return this.createThing("row", config);
+
+ const domain = config.entity.split(".", 1)[0];
+ Object.assign(config, {type: DEFAULT_ROWS[domain] || "text"});
+ return this.createThing("entity-row", config);
+ }
+
+ static get deviceID() {
+ const ID_STORAGE_KEY = 'lovelace-player-device-id';
+ if(window['fully'] && typeof fully.getDeviceId === "function")
+ return fully.getDeviceId();
+ if(!localStorage[ID_STORAGE_KEY])
+ {
+ const s4 = () => {
+ return Math.floor((1+Math.random())*100000).toString(16).substring(1);
+ }
+ localStorage[ID_STORAGE_KEY] = `${s4()}${s4()}-${s4()}${s4()}`;
+ }
+ return localStorage[ID_STORAGE_KEY];
+ }
+
+ static moreInfo(entity) {
+ this.fireEvent("hass-more-info", {entityId: entity});
+ }
+
+ static longpress(element) {
+ customElements.whenDefined("long-press").then(() => {
+ const longpress = document.body.querySelector("long-press");
+ longpress.bind(element);
+ });
+ return element;
+ }
+
+ static hasTemplate(text) {
+ return /\[\[\s+.*\s+\]\]/.test(text);
+ }
+
+ static parseTemplateString(str, specialData = {}) {
+ if(typeof(str) !== "string") return text;
+ const FUNCTION = /^[a-zA-Z0-9_]+\(.*\)$/;
+ const EXPR = /([^=<>!]+)\s*(==|!=|<|>|<=|>=)\s*([^=<>!]+)/;
+ const SPECIAL = /^\{.+\}$/;
+ const STRING = /^"[^"]*"|'[^']*'$/;
+
+ if(typeof(specialData) === "string") specialData = {};
+ specialData = Object.assign({
+ user: this.hass.user.name,
+ browser: this.deviceID,
+ hash: location.hash.substr(1) || ' ',
+ }, specialData);
+
+ const _parse_function = (str) => {
+ let args = [str.substr(0, str.indexOf('(')).trim()]
+ str = str.substr(str.indexOf('(')+1);
+ while(str) {
+ let index = 0;
+ let parens = 0;
+ let quote = false;
+ while(str[index]) {
+ let c = str[index++];
+
+ if(c === quote && index > 1 && str[index-2] !== "\\")
+ quote = false;
+ else if(`"'`.includes(c))
+ quote = c;
+ if(quote) continue;
+
+ if(c === '(')
+ parens = parens + 1;
+ else if(c === ')') {
+ parens = parens - 1;
+ continue
+ }
+ if(parens > 0) continue;
+
+ if(",)".includes(c)) break;
+ }
+ args.push(str.substr(0, index-1).trim());
+ str = str.substr(index);
+ }
+ return args;
+ };
+
+ const _parse_special = (str) => {
+ str = str.substr(1, str.length - 2);
+ return specialData[str] || `{${str}}`;
+ };
+
+ const _parse_entity = (str) => {
+ str = str.split(".");
+ let v;
+ if(str[0].match(SPECIAL)) {
+ v = _parse_special(str.shift());
+ v = this.hass.states[v] || v;
+ } else {
+ v = this.hass.states[`${str.shift()}.${str.shift()}`];
+ if(!str.length) return v['state'];
+ }
+ str.forEach(item => v=v[item]);
+ return v;
+ }
+
+ const _eval_expr = (str) => {
+ str = EXPR.exec(str);
+ if(str === null) return false;
+ const lhs = this.parseTemplateString(str[1]);
+ const rhs = this.parseTemplateString(str[3]);
+ var expr = ''
+ if(parseFloat(lhs) != lhs)
+ expr = `"${lhs}" ${str[2]} "${rhs}"`;
+ else
+ expr = `${parseFloat(lhs)} ${str[2]} ${parseFloat(rhs)}`
+ return eval(expr);
+ }
+
+ const _eval_function = (args) => {
+ if(args[0] === "if") {
+ if(_eval_expr(args[1]))
+ return this.parseTemplateString(args[2]);
+ return this.parseTemplateString(args[3]);
+ }
+ }
+
+ try {
+ str = str.trim();
+ if(str.match(STRING))
+ return str.substr(1, str.length - 2);
+ if(str.match(SPECIAL))
+ return _parse_special(str);
+ if(str.match(FUNCTION))
+ return _eval_function(_parse_function(str));
+ if(str.includes("."))
+ return _parse_entity(str);
+ return str;
+ } catch (err) {
+ return `[[ Template matching failed: ${str} ]]`;
+ }
+ }
+
+ static parseTemplate(text, data = {}) {
+ if(typeof(text) !== "string") return text;
+ // Note: .*? is javascript regex syntax for NON-greedy matching
+ var RE_template = /\[\[\s(.*?)\s\]\]/g;
+ text = text.replace(RE_template, (str, p1, offset, s) => this.parseTemplateString(p1, data));
+ return text;
+ }
+
+ static args(script=null) {
+ script = script || document.currentScript;
+ var url = script.src;
+ url = url.substr(url.indexOf("?")+1)
+ let args = {};
+ url.split("&").forEach((a) => {
+ if(a.indexOf("=")) {
+ let parts = a.split("=");
+ args[parts[0]] = parts[1]
+ } else {
+ args[a] = true;
+ }
+ });
+ return args;
+ }
+
+ static localize(key, def="") {
+ const language = this.hass.language;
+ if(this.hass.resources[language] && this.hass.resources[language][key])
+ return this.hass.resources[language][key];
+ return def;
+ }
+
+ static popUp(title, message, large=false) {
+ let popup = document.createElement('div');
+ popup.innerHTML = `
+
+
+
+
+ ${title}
+
+
+ `;
+ popup.appendChild(message);
+ this.moreInfo(Object.keys(this.hass.states)[0]);
+ let moreInfo = document.querySelector("home-assistant")._moreInfoEl;
+ moreInfo._page = "none";
+ moreInfo.shadowRoot.appendChild(popup);
+ moreInfo.large = large;
+ document.querySelector("home-assistant").provideHass(message);
+
+ setTimeout(() => {
+ let interval = setInterval(() => {
+ if (moreInfo.getAttribute('aria-hidden')) {
+ popup.parentNode.removeChild(popup);
+ clearInterval(interval);
+ }
+ }, 100)
+ }, 1000);
+ return moreInfo;
+ }
+ static closePopUp() {
+ let moreInfo = document.querySelector("home-assistant")._moreInfoEl;
+ if (moreInfo) moreInfo.close()
+ }
+
+ static logger(message, script=null) {
+ if(!('debug' in this.args(script))) return;
+
+ if(typeof message !== "string")
+ message = JSON.stringify(message);
+ console.log(`%cDEBUG:%c ${message}`,
+ "color: blue; font-weight: bold", "");
+ }
+
+});
+
+// Global definition of cardTools
+var cardTools = customElements.get('card-tools');
+
+console.info(`%cCARD-TOOLS IS INSTALLED
+%cDeviceID: ${customElements.get('card-tools').deviceID}`,
+"color: green; font-weight: bold",
+"");
diff --git a/www/community/lovelace-card-tools/card-tools.js.gz b/www/community/lovelace-card-tools/card-tools.js.gz
new file mode 100644
index 0000000..7cbadc1
Binary files /dev/null and b/www/community/lovelace-card-tools/card-tools.js.gz differ
diff --git a/www/community/lovelace-layout-card/layout-card.js b/www/community/lovelace-layout-card/layout-card.js
new file mode 100644
index 0000000..dbfe21c
--- /dev/null
+++ b/www/community/lovelace-layout-card/layout-card.js
@@ -0,0 +1,194 @@
+customElements.whenDefined('card-tools').then(() => {
+let cardTools = customElements.get('card-tools');
+class LayoutCard extends cardTools.LitElement {
+
+ async setConfig(config) {
+ this.config = config;
+ this.layout = config.layout || 'auto';
+ this.minCols = config.column_num || 1;
+ this.maxCols = config.max_columns || 100;
+ this.colWidth = config.column_width || 400;
+ this.maxWidth = config.max_width || 500;
+ this.minHeight = config.min_height || 5;
+ this.rtl = config.rtl || false;
+ this.cardSize = 1;
+
+ this.make_cards();
+
+ window.addEventListener('resize', () => this.build());
+ window.addEventListener('hass-open-menu', () => setTimeout(() => this.build(), 100));
+ window.addEventListener('hass-close-menu', () => setTimeout(() => this.build(), 100));
+ window.addEventListener('location-changed', () => {
+ if(location.hash === "") setTimeout(() =>
+ this.build(), 100)
+ });
+ if(config.rebuild)
+ window.setTimeout(() => this.build(), config.rebuild);
+ }
+
+ render() {
+ return cardTools.LitHtml`
+
+ `;
+ }
+
+ firstUpdated() {
+ if(this.parentElement && this.parentElement.id !== "view")
+ {
+ this.style.padding = "0";
+ }
+ if(this.rtl)
+ this.shadowRoot.querySelector("#columns").style.flexDirection = 'row-reverse';
+ this.build();
+ this._cardModder = {
+ target: this,
+ styles: this.shadowRoot.querySelector("style")
+ };
+ }
+
+ static get styles() {
+ return cardTools.LitCSS`
+ :host {
+ padding: 8px 4px 0;
+ display: block;
+ }
+
+ #columns {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ }
+
+ .column {
+ flex-basis: 0;
+ flex-grow: 1;
+ overflow-x: hidden;
+ }
+
+ .column > * {
+ display: block;
+ margin: 4px 4px 8px;
+ }
+
+ .column > *:first-child {
+ margin-top: 0;
+ }
+ `;
+ }
+
+ make_cards() {
+ this._cards = this.config.cards.map((c) => {
+ if (typeof c === 'string') return c;
+ const card = cardTools.createCard(c);
+ if(this._hass) card.hass = this._hass;
+ this.appendChild(card); // Place card in DOM to get size
+ return card;
+ });
+ }
+
+ update_columns() {
+ const width = (this.shadowRoot && this.shadowRoot.querySelector("#columns").clientWidth) || (this.parentElement && this.parentElement.clientWidth);
+ this.colNum = Math.floor(width / this.colWidth) || 1;
+ this.colNum = Math.max(this.colNum, this.minCols);
+ this.colNum = Math.min(this.colNum, this.maxCols);
+ }
+
+ build() {
+ if (this.offsetParent === null) return;
+ const root = this.shadowRoot.querySelector("#columns");
+ while(root.lastChild) {
+ root.removeChild(root.lastChild);
+ }
+
+ this.update_columns();
+
+ if(!this._cards) this.make_cards();
+
+ let cols = [];
+ let colSize = [];
+ for(let i = 0; i < this.colNum; i++) {
+ cols.push([]);
+ colSize.push(0);
+ }
+
+ const shortestCol = () => {
+ let i = 0;
+ for(let j = 0; j < this.colNum; j++) {
+ if(colSize[j] < this.min_height)
+ return j;
+ if(colSize[j] < colSize[i])
+ i = j;
+ }
+ return i;
+ }
+
+ let i = 0;
+ this._cards.forEach((c) => {
+ const isBreak = (typeof(c) === 'string');
+ const sz = c.getCardSize ? c.getCardSize() : 1;
+
+ switch(this.layout) {
+ case 'horizontal':
+ if(i >= this.colNum) i = 0;
+ i += 1;
+ if(isBreak) break;
+ cols[i-1].push(c);
+ colSize[i-1] += sz;
+ break;
+ case 'vertical':
+ if(isBreak){
+ i += 1;
+ if(i >= this.colNum)
+ i = 0;
+ break;
+ }
+ cols[i].push(c);
+ colSize[i] += sz;
+ break;
+ case 'auto':
+ default:
+ if(isBreak) break;
+ cols[shortestCol()].push(c);
+ colSize[shortestCol()] += sz;
+ break;
+ }
+ });
+
+ cols = cols.filter((c) => c.length > 0);
+ cols.forEach((c, i) => {
+ const div = document.createElement('div');
+ div.classList.add('column');
+ c.forEach((e) => div.appendChild(e));
+ root.appendChild(div);
+ if(cols.length > 1 && typeof(this.maxWidth) === 'object') {
+ div.style.setProperty('max-width', this.maxWidth[i]);
+ } else {
+ div.style.setProperty('max-width', this.maxWidth+'px');
+ }
+ });
+
+ this.cardSize = Math.max.apply(null, colSize);
+ }
+
+ set hass(hass) {
+ this._hass = hass;
+ if(this._cards)
+ this._cards
+ .filter((c) => typeof(c) !== 'string')
+ .forEach((c) => c.hass = hass);
+ }
+
+ getCardSize() {
+ return this.cardSize;
+ }
+
+}
+
+customElements.define('layout-card', LayoutCard);
+});
+window.setTimeout(() => {
+ if(customElements.get('card-tools')) return;
+ customElements.define('layout-card', class extends HTMLElement{
+ setConfig() { throw new Error("Can't find card-tools. See https://github.com/thomasloven/lovelace-card-tools");}
+ });
+}, 2000);
diff --git a/www/community/lovelace-layout-card/layout-card.js.gz b/www/community/lovelace-layout-card/layout-card.js.gz
new file mode 100644
index 0000000..95f2073
Binary files /dev/null and b/www/community/lovelace-layout-card/layout-card.js.gz differ
diff --git a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js
new file mode 100644
index 0000000..435f838
--- /dev/null
+++ b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js
@@ -0,0 +1,203 @@
+class MultipleEntityRow extends Polymer.Element {
+
+ static get template() {
+ return Polymer.html`
+
+
+
+
+ [[entityName(_config)]]
+
+
+ [[entityName(info)]] [[entityState(info)]]
+
+
+
+
+
+
+
+
+
[[entityName(primary)]]
+
[[entityState(primary)]]
+
+
+
+
+
[[entityName(secondary)]]
+
[[entityState(secondary)]]
+
+
+
+
+ [[entityState(_config)]]
+
+
+
+
+
+
+
+
`;
+ }
+
+ primaryMoreInfo(e) {
+ e.stopPropagation();
+ this.fireEvent(this._config.primary.entity)
+ }
+
+ secondaryMoreInfo(e) {
+ e.stopPropagation();
+ this.fireEvent(this._config.secondary.entity)
+ }
+
+ entityName(data) {
+ return data && data.stateObj && data.name !== false ? this.computeStateName(data.stateObj, data.name) : null;
+ }
+
+ entityState(data) {
+ if (!data || !data.stateObj) return this._hass.localize('state.default.unavailable');
+ return data.attribute
+ ? data.stateObj.attributes[data.attribute]
+ ? `${data.stateObj.attributes[data.attribute]} ${data.unit ? data.unit : ''}`
+ : this._hass.localize('state.default.unavailable')
+ : this.computeStateValue(data.stateObj, data.unit);
+ }
+
+ computeStateName(stateObj, name) {
+ return name || (stateObj.attributes.friendly_name === undefined
+ ? stateObj.entity_id.substr(stateObj.entity_id.indexOf('.') + 1).replace(/_/g, ' ')
+ : stateObj.attributes.friendly_name || '');
+ }
+
+ computeStateValue(stateObj, unit) {
+ let display;
+ const domain = stateObj.entity_id.substr(0, stateObj.entity_id.indexOf("."));
+
+ if (domain === "binary_sensor") {
+ if (stateObj.attributes.device_class) {
+ display = this._hass.localize(`state.${domain}.${stateObj.attributes.device_class}.${stateObj.state}`);
+ }
+ if (!display) {
+ display = this._hass.localize(`state.${domain}.default.${stateObj.state}`);
+ }
+ } else if ((unit || stateObj.attributes.unit_of_measurement) && !["unknown", "unavailable"].includes(stateObj.state)) {
+ display = `${stateObj.state} ${stateObj.attributes.unit_of_measurement}`;
+ } else if (domain === "zwave") {
+ display = ["initializing", "dead"].includes(stateObj.state)
+ ? this._hass.localize(`state.zwave.query_stage.${stateObj.state}`, 'query_stage', stateObj.attributes.query_stage)
+ : this._hass.localize(`state.zwave.default.${stateObj.state}`);
+ } else {
+ display = this._hass.localize(`state.${domain}.${stateObj.state}`);
+ }
+
+ return display ||
+ this._hass.localize(`state.default.${stateObj.state}`) ||
+ this._hass.localize(`component.${domain}.state.${stateObj.state}`) ||
+ stateObj.state;
+ }
+
+ setConfig(config) {
+ if (!config.entity) throw new Error('Please define an entity.');
+ if (config.primary && !config.primary.entity) throw new Error('Please define a primary entity.');
+ if (config.secondary && !config.secondary.entity) throw new Error('Please define a secondary entity.');
+
+ this._config = config;
+ this.displayToggle = config.toggle === true;
+ this.displayValue = !this.displayToggle && !config.hide_state;
+ this.displayPrimary = config.primary && config.primary.entity;
+ this.displaySecondary = config.secondary && config.secondary.entity;
+ this.displayInfo = config.info && config.info.entity;
+ this.displayLastChanged = !this.displayInfo && config.secondary_info === 'last-changed';
+ }
+
+ set hass(hass) {
+ this._hass = hass;
+
+ if (hass && this._config) {
+ const stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
+ if (stateObj) {
+ this._config.stateObj = stateObj;
+
+ this.primary = Object.assign({}, this._config.primary, {
+ stateObj: this.displayPrimary && this._config.primary.entity in hass.states ?
+ hass.states[this._config.primary.entity] : null
+ });
+ this.secondary = Object.assign({}, this._config.secondary, {
+ stateObj: this.displaySecondary && this._config.secondary.entity in hass.states ?
+ hass.states[this._config.secondary.entity] : null
+ });
+ this.info = Object.assign({}, this._config.info, {
+ stateObj: this.displayInfo && this._config.info.entity in hass.states ?
+ hass.states[this._config.info.entity] : null
+ });
+ }
+ }
+ }
+
+ fireEvent(entity, options = {}) {
+ const event = new Event('hass-more-info', {
+ bubbles: options.bubbles || true,
+ cancelable: options.cancelable || true,
+ composed: options.composed || true,
+ });
+ event.detail = {entityId: entity};
+ this.shadowRoot.dispatchEvent(event);
+ return event;
+ }
+}
+
+customElements.define('multiple-entity-row', MultipleEntityRow);
diff --git a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz
new file mode 100644
index 0000000..2ec8419
Binary files /dev/null and b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz differ
diff --git a/www/community/lovelace-slider-entity-row/slider-entity-row.js b/www/community/lovelace-slider-entity-row/slider-entity-row.js
new file mode 100644
index 0000000..417548f
--- /dev/null
+++ b/www/community/lovelace-slider-entity-row/slider-entity-row.js
@@ -0,0 +1,53 @@
+!function(t){var e={};function s(i){if(e[i])return e[i].exports;var a=e[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,s),a.l=!0,a.exports}s.m=t,s.c=e,s.d=function(t,e,i){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(s.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)s.d(i,a,function(e){return t[e]}.bind(null,a));return i},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=0)}([function(t,e,s){"use strict";s.r(e);const i=Object.getPrototypeOf(customElements.get("home-assistant-main")),a=i.prototype.html,r=i.prototype.css;class n{constructor(t){this._config=t}set hass(t){this._hass=t,this.stateObj=this._config.entity in t.states?t.states[this._config.entity]:null}get value(){return this._value?Math.round(this._value/this.step)*this.step:0}set value(t){t!==this.value&&(this._value=t)}get string(){return`${this.value}`}get hidden(){return!1}get hasSlider(){return!0}get hasToggle(){return!0}get isOff(){return 0===this.value}get min(){return void 0!==this._config.min?this._config.min:void 0!==this._min?this._min:0}get max(){return void 0!==this._config.max?this._config.max:void 0!==this._max?this._max:100}get step(){return void 0!==this._config.step?this._config.step:void 0!==this._step?this._step:5}}const u={light:class extends n{get _value(){return"on"===this.stateObj.state?Math.ceil(100*this.stateObj.attributes.brightness/255):0}set _value(t){(t=Math.ceil(t/100*255))?this._hass.callService("light","turn_on",{entity_id:this.stateObj.entity_id,brightness:t}):this._hass.callService("light","turn_off",{entity_id:this.stateObj.entity_id})}get string(){return"off"===this.stateObj.state?this._hass.localize("state.default.off"):`${this.value} %`}get hasSlider(){return"brightness"in this.stateObj.attributes||!!("supported_features"in this.stateObj.attributes&&1&this.stateObj.attributes.supported_features)}},media_player:class extends n{get _value(){return"on"===this.stateObj.is_volume_muted?0:Math.ceil(100*this.stateObj.attributes.volume_level)}set _value(t){t/=100,this._hass.callService("media_player","volume_set",{entity_id:this.stateObj.entity_id,volume_level:t})}get isOff(){return"off"===this.stateObj.state}get string(){return this.stateObj.attributes.is_volume_muted?"-":this.stateObj.attributes.volume_level?`${this.value} %`:this._hass.localize("state.media_player.off")}get hasToggle(){return!1}},climate:class extends n{get _value(){return this.stateObj.attributes.temperature}set _value(t){this._hass.callService("climate","set_temperature",{entity_id:this.stateObj.entity_id,temperature:t})}get string(){return"off"===this.stateObj.attributes.operation_mode?this._hass.localize("state.climate.off"):`${this.value} ${this._hass.config.unit_system.temperature}`}get isOff(){return"off"===this.stateObj.attributes.operation_mode}get _min(){return this.stateObj.attributes.min_temp}get _max(){return this.stateObj.attributes.max_temp}get _step(){return 1}},cover:class extends n{get _value(){return"open"===this.stateObj.state?this.stateObj.attributes.current_position:0}set _value(t){this._hass.callService("cover","set_cover_position",{entity_id:this.stateObj.entity_id,position:t})}get string(){return this.hasSlider?"closed"===this.stateObj.state?this._hass.localize("state.cover.closed"):`${this.value} %`:""}get hasToggle(){return!1}get hasSlider(){return"current_position"in this.stateObj.attributes||!!("supported_features"in this.stateObj.attributes&&4&this.stateObj.attributes.supported_features)}get _step(){return 10}},fan:class extends n{get _value(){return"off"!==this.stateObj.state?this.stateObj.attributes.speed_list.indexOf(this.stateObj.attributes.speed):0}set _value(t){t in this.stateObj.attributes.speed_list?this._hass.callService("fan","turn_on",{entity_id:this.stateObj.entity_id,speed:this.stateObj.attributes.speed_list[t]}):this._hass.callService("fan","turn_off",{entity_id:this.stateObj.entity_id})}get string(){return"off"===this.stateObj.state?this._hass.localize("state.default.off"):this.stateObj.attributes.speed}get hasSlider(){return"speed"in this.stateObj.attributes}get _max(){return this.stateObj.attributes.speed_list.length-1}get _step(){return 1}},input_number:class extends n{get _value(){return this.stateObj.state}set _value(t){this._hass.callService("input_number","set_value",{entity_id:this.stateObj.entity_id,value:t})}get string(){return`${parseFloat(this.stateObj.state)}`}get isOff(){return!1}get hasToggle(){return!1}get hasSlider(){return"slider"===this.stateObj.attributes.mode}get _min(){return this.stateObj.attributes.min}get _max(){return this.stateObj.attributes.max}get _step(){return this.stateObj.attributes.step}},input_select:class extends n{get _value(){return this.stateObj.attributes.options.indexOf(this.stateObj.state)}set _value(t){t in this.stateObj.attributes.options&&this._hass.callService("input_select","select_option",{entity_id:this.stateObj.entity_id,option:this.stateObj.attributes.options[t]})}get string(){return this.stateObj.state}get isOff(){return!1}get hasToggle(){return!1}get hasSlider(){return this.stateObj.attributes.options&&this.stateObj.attributes.options.length>0}get _max(){return this.stateObj.attributes.options.length-1}get _step(){return 1}}};customElements.define("slider-entity-row",class extends i{static get properties(){return{hass:{}}}setConfig(t){this._config=t;const e=t.entity.split(".")[0],s=u[e];if(!s)throw new Error(`Unsupported entity type: ${e}`);this.ctrl=new s(t)}render(){const t=this.ctrl;t.hass=this.hass;const e=a`
+ t.value=this.shadowRoot.querySelector("ha-slider").value}
+ class=${this._config.full_row?"full":""}
+ >
+ `,s=a`
+
+ `,i=a`
+ t.stopPropagation()}>
+ ${"unavailable"===t.stateObj.state?a`
+
+ unavailable
+
+ `:a`
+ ${this._config.hide_when_off&&t.isOff||!t.hasSlider?"":e}
+ ${this._config.hide_state||this._config.toggle?"":a`
+
+ ${t.string}
+
+ `}
+ ${this._config.toggle&&t.hasToggle?s:""}
+ `}
+
+ `;return this._config.full_row?i:a`
+ ${i}
+ `}static get styles(){return r`
+ .wrapper {
+ display: flex;
+ align-items: center;
+ height: 40px;
+ }
+ .state {
+ min-width: 45px;
+ text-align: end;
+ }
+ ha-entity-toggle {
+ margin-left: 8px;
+ }
+ ha-slider.full {
+ width: 100%;
+ }
+ `}})}]);
\ No newline at end of file
diff --git a/www/community/lovelace-slider-entity-row/slider-entity-row.js.gz b/www/community/lovelace-slider-entity-row/slider-entity-row.js.gz
new file mode 100644
index 0000000..216a6eb
Binary files /dev/null and b/www/community/lovelace-slider-entity-row/slider-entity-row.js.gz differ
diff --git a/www/community/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js b/www/community/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js
new file mode 100644
index 0000000..61afd85
--- /dev/null
+++ b/www/community/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js
@@ -0,0 +1,221 @@
+class XiaomiVacuumCard extends Polymer.Element {
+
+ static get template() {
+ return Polymer.html`
+
+
+
+ [[name]]
+
+
+
+
[[_config.labels.status]]: [[stateObj.attributes.status]]
+
[[_config.labels.battery]]: [[stateObj.attributes.battery_level]] %
+
[[_config.labels.mode]]: [[stateObj.attributes.fan_speed]]
+
+
+
+
[[_config.labels.main_brush]]: [[stateObj.attributes.main_brush_left]] [[_config.labels.hours]]
+
[[_config.labels.side_brush]]: [[stateObj.attributes.side_brush_left]] [[_config.labels.hours]]
+
[[_config.labels.filter]]: [[stateObj.attributes.filter_left]] [[_config.labels.hours]]
+
[[_config.labels.sensor]]: [[stateObj.attributes.sensor_dirty_left]] [[_config.labels.hours]]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+
+ moreInfo() { this.fireEvent('hass-more-info'); }
+ startVaccum() { this.callService(this._config.service.start); }
+ pauseVacuum() { this.callService(this._config.service.pause); }
+ stopVacuum() { this.callService(this._config.service.stop); }
+ locateVacuum() { this.callService(this._config.service.locate); }
+ returnVacuum() { this.callService(this._config.service.return); }
+ cleanSpot() { this.callService(this._config.service.spot); }
+
+ callService(service) {
+ this._hass.callService('vacuum', service, {entity_id: this._config.entity});
+ }
+
+ fireEvent(type, options = {}) {
+ const event = new Event(type, {
+ bubbles: options.bubbles || true,
+ cancelable: options.cancelable || true,
+ composed: options.composed || true,
+ });
+ event.detail = {entityId: this._config.entity};
+ this.shadowRoot.dispatchEvent(event);
+ return event;
+ }
+
+ getCardSize() {
+ if (this.name && this.showButtons) return 5;
+ if (this.name || this.showButtons) return 4;
+ return 3;
+ }
+
+ setConfig(config) {
+ const labels = {
+ status: 'Status',
+ battery: 'Battery',
+ mode: 'Mode',
+ main_brush: 'Main Brush',
+ side_brush: 'Side Brush',
+ filter: 'Filter',
+ sensor: 'Sensor',
+ hours: 'h',
+ };
+
+ const services = {
+ start: 'start',
+ pause: 'pause',
+ stop: 'stop',
+ locate: 'locate',
+ return: 'return_to_base',
+ spot: 'clean_spot',
+ };
+
+ const buttons = {
+ start: true,
+ pause: true,
+ stop: true,
+ spot: false,
+ locate: true,
+ return: true,
+ };
+
+ const vendors = {
+ xiaomi: {
+ image: '/local/img/vacuum.png',
+ details: true,
+ },
+ ecovacs: {
+ image: '/local/img/vacuum_ecovacs.png',
+ details: false,
+ buttons: {
+ stop: false,
+ spot: true,
+ },
+ service: {
+ start: 'turn_on',
+ pause: 'stop',
+ stop: 'turn_off',
+ },
+ }
+ };
+
+ if (!config.entity) throw new Error('Please define an entity.');
+ if (config.entity.split('.')[0] !== 'vacuum') throw new Error('Please define a vacuum entity.');
+ if (config.vendor && !config.vendor in vendors) throw new Error('Please define a valid vendor.');
+
+ const vendor = vendors[config.vendor] || vendors.xiaomi;
+
+ this.showDetails = vendor.details;
+ this.showButtons = config.buttons !== false;
+
+ config.service = Object.assign({}, services, vendor.service);
+ config.buttons = Object.assign({}, buttons, vendor.buttons, config.buttons);
+ config.labels = Object.assign({}, labels, config.labels);
+
+ this.contentText = `color: ${config.image !== false ? 'white; text-shadow: 0 0 10px black;' : 'var(--primary-text-color)'}`;
+ this.contentStyle = `padding: ${this.showButtons ? '16px 16px 4px' : '16px'}; ${this.contentText}`;
+ this.backgroundImage = config.image !== false ? `background-image: url('${config.image || vendor.image}')` : '';
+
+ this._config = config;
+ }
+
+ set hass(hass) {
+ this._hass = hass;
+
+ if (hass && this._config) {
+ this.stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
+
+ if (this.stateObj) {
+ this.name = this._config.name !== false && (this._config.name || this.stateObj.attributes.friendly_name);
+ }
+ }
+ }
+}
+
+customElements.define('xiaomi-vacuum-card', XiaomiVacuumCard);
diff --git a/www/community/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js.gz b/www/community/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js.gz
new file mode 100644
index 0000000..ef5f3ae
Binary files /dev/null and b/www/community/lovelace-xiaomi-vacuum-card/xiaomi-vacuum-card.js.gz differ
diff --git a/www/community/mini-media-player/mini-media-player.js b/www/community/mini-media-player/mini-media-player.js
new file mode 100644
index 0000000..80c424e
--- /dev/null
+++ b/www/community/mini-media-player/mini-media-player.js
@@ -0,0 +1 @@
+(function(){"use strict";function a(){const b=sa(["",""]);return a=function(){return b},b}function b(){const a=sa(["",""]);return b=function(){return a},a}function c(){const a=sa(["\n "]);return c=function(){return a},a}function d(){const a=sa(["\n \n ","\n ","\n
"]);return d=function(){return a},a}function e(){const a=sa(["\n \n "," ","\n
"]);return e=function(){return a},a}function f(){const a=sa(["\n \n \n
"]);return f=function(){return a},a}function g(){const a=sa(["\n \n
"]);return g=function(){return a},a}function h(){const a=sa([""]);return h=function(){return a},a}function i(){const a=sa(["\n \n \n "]);return i=function(){return a},a}function j(){const a=sa(["\n \n \n "]);return j=function(){return a},a}function k(){const a=sa(["\n \n \n ","\n
\n \n
\n ","\n
\n ","\n ","\n
\n
\n \n
\n
\n ","\n \n \n ","\n \n \n
\n
\n \n \n \n
\n \n "]);return k=function(){return a},a}function l(){const a=sa(["\n :host {\n display: flex;\n line-height: 40px;\n max-height: 40px;\n }\n :host([flow]) mmp-media-controls {\n max-width: unset;\n }\n mmp-media-controls {\n max-width: 200px;\n }\n .group-button {\n height: 34px;\n width: 34px;\n min-width: 34px;\n margin: 3px;\n }\n paper-icon-button {\n min-width: 40px;\n }\n "]);return l=function(){return a},a}function m(){const a=sa(["\n \n ","\n \n "]);return m=function(){return a},a}function n(){const a=sa(["\n \n "]);return n=function(){return a},a}function o(){const a=sa(["\n \n "]);return o=function(){return a},a}function p(){const a=sa(["\n \n "]);return p=function(){return a},a}function q(){const a=sa(["\n \n "]);return q=function(){return a},a}function r(){const a=sa(["\n \n "]);return r=function(){return a},a}function s(){const a=sa(["\n \n \n "]);return s=function(){return a},a}function t(){const a=sa(["\n ","\n ","\n ","\n ","\n ","\n ","\n "]);return t=function(){return a},a}function u(){const a=sa(["\n \n ","\n \n "]);return u=function(){return a},a}function v(){const a=sa(["\n :host {\n display: flex;\n width: 100%;\n }\n .flex {\n display: flex;\n flex: 1;\n justify-content: space-between;\n }\n ha-slider {\n max-width: none;\n min-width: 100px;\n width: 100%;\n }\n paper-icon-button {\n min-width: 40px;\n }\n .mmp-media-controls__volume {\n flex: 100;\n max-height: 40px;\n }\n .mmp-media-controls__volume.--buttons {\n justify-content: left;\n }\n .mmp-media-controls__media {\n direction: ltr;\n max-width: calc(40px * 3);\n margin-right: 0;\n margin-left: auto;\n }\n .mmp-media-controls__media[flow] {\n max-width: none;\n }\n .mmp-media-controls__shuffle {\n flex: 3;\n flex-shrink: 200;\n justify-content: center;\n }\n .mmp-media-controls__shuffle paper-icon-button {\n height: 36px;\n width: 36px;\n min-width: 36px;\n margin: 2px;\n }\n "]);return v=function(){return a},a}function w(){const a=sa(["\n \n \n "]);return w=function(){return a},a}function x(){const a=sa(["\n \n \n "]);return x=function(){return a},a}function y(){const a=sa(["\n \n \n "]);return y=function(){return a},a}function z(){const a=sa(["\n \n \n "]);return z=function(){return a},a}function A(){const a=sa(["\n "]);return A=function(){return a},a}function B(){const a=sa(["\n \n ","\n \n \n
"]);return B=function(){return a},a}function C(){const a=sa([""]);return C=function(){return a},a}function D(){const a=sa(["\n \n "]);return D=function(){return a},a}function E(){const a=sa([""]);return E=function(){return a},a}function F(){const a=sa(["\n \n "]);return F=function(){return a},a}function G(){const a=sa([""]);return G=function(){return a},a}function H(){const a=sa(["\n ","\n ","\n ","\n "]);return H=function(){return a},a}function I(){const a=sa(["\n :host {\n max-width: 120px;\n min-width: 40px;\n }\n :host([full]) {\n max-width: none;\n }\n "]);return I=function(){return a},a}function J(){const a=sa(["\n \n "]);return J=function(){return a},a}function K(){const a=sa(["\n :host {\n max-width: 120px;\n min-width: 40px;\n }\n :host([full]) {\n max-width: none;\n }\n "]);return K=function(){return a},a}function L(){const a=sa(["\n \n "]);return L=function(){return a},a}function M(){const a=sa(["\n .mmp-progress {\n cursor: pointer;\n left: 0; right: 0; bottom: 0;\n position: absolute;\n pointer-events: auto;\n min-height: 10px;\n }\n .mmp-progress__duration {\n display: flex;\n justify-content: space-between;\n font-size: .8em;\n margin: 8px calc(var(--ha-card-border-radius, 4px) / 2);\n margin-top: 0;\n padding: 0 6px;\n }\n paper-progress {\n height: var(--paper-progress-height, 4px);\n bottom: 0;\n position: absolute;\n width: 100%;\n --paper-progress-active-color: var(--mmp-accent-color);\n --paper-progress-container-color: rgba(100,100,100,.15);\n --paper-progress-transition-duration: 1s;\n --paper-progress-transition-timing-function: linear;\n --paper-progress-transition-delay: 0s;\n }\n .mmp-progress[paused] paper-progress {\n --paper-progress-active-color: var(--disabled-text-color, rgba(150,150,150,.5));\n }\n "]);return M=function(){return a},a}function N(){const a=sa([""]);return N=function(){return a},a}function O(){const a=sa(["\n \n ","\n ","\n
\n "]);return O=function(){return a},a}function P(){const a=sa(["\n \n "]);return P=function(){return a},a}function Q(){const a=sa(["\n :host {\n align-items: center;\n margin-left: 8px;\n display: flex;\n }\n .mmp-tts__input {\n cursor: text;\n flex: 1;\n margin-right: 8px;\n --paper-input-container-input: {\n font-size: 1em;\n };\n }\n ha-card[rtl] .mmp-tts__input {\n margin-right: auto;\n margin-left: 8px;\n }\n .mmp-tts__button {\n margin: 0;\n height: 30px;\n padding: 0 .4em;\n }\n paper-input {\n opacity: .75;\n --paper-input-container-color: var(--mmp-text-color);\n --paper-input-container-focus-color: var(--mmp-text-color);\n --paper-input-container: {\n padding: 0;\n };\n }\n paper-input[focused] {\n opacity: 1;\n }\n\n ha-card[artwork*='cover'][has-artwork] paper-input {\n --paper-input-container-focus-color: #FFFFFF;\n }\n ha-card[artwork*='cover'][has-artwork] paper-input {\n --paper-input-container-color: #FFFFFF;\n --paper-input-container-input-color: #FFFFFF;\n }\n "]);return Q=function(){return a},a}function R(){const a=sa(["\n \n \n \n SEND\n \n "]);return R=function(){return a},a}function S(){const a=sa(["\n .mmp-shortcuts__buttons {\n box-sizing: border-box;\n display: flex;\n flex-wrap: wrap;\n margin-top: 8px;\n }\n .mmp-shortcuts__button {\n min-width: calc(50% - 8px);\n flex: 1;\n }\n .mmp-shortcuts__button > div {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n }\n .mmp-shortcuts__button > div[align='left'] {\n justify-content: flex-start;\n }\n .mmp-shortcuts__button > div[align='right'] {\n justify-content: flex-end;\n }\n .mmp-shortcuts__button[columns='1'] {\n min-width: calc(100% - 8px);\n }\n .mmp-shortcuts__button[columns='3'] {\n min-width: calc(33.33% - 8px);\n }\n .mmp-shortcuts__button[columns='4'] {\n min-width: calc(25% - 8px);\n }\n .mmp-shortcuts__button[columns='5'] {\n min-width: calc(20% - 8px);\n }\n .mmp-shortcuts__button > div > span {\n line-height: 24px;\n text-transform: initial;\n }\n .mmp-shortcuts__button > div > *:nth-child(2) {\n margin-left: 4px;\n }\n "]);return S=function(){return a},a}function T(){const a=sa(["\n ","\n ","\n "]);return T=function(){return a},a}function U(){const a=sa(["",""]);return U=function(){return a},a}function V(){const a=sa([""]);return V=function(){return a},a}function W(){const a=sa(["\n \n \n ","\n ","\n
\n "]);return W=function(){return a},a}function X(){const a=sa(["\n \n ","\n
\n "]);return X=function(){return a},a}function Y(){const a=sa(["\n \n \n "]);return Y=function(){return a},a}function Z(){const a=sa([""]);return Z=function(){return a},a}function $(){const a=sa(["\n :host {\n display: block;\n }\n :host([faded]) {\n opacity: .75;\n }\n :host[small] .mmp-dropdown__label {\n max-width: 60px;\n display: block;\n position: relative;\n width: auto;\n text-transform: initial;\n }\n :host[full] .mmp-dropdown__label {\n max-width: none;\n }\n .mmp-dropdown {\n padding: 0;\n display: block;\n }\n .mmp-dropdown__button {\n display: flex;\n font-size: 1em;\n justify-content: space-between;\n align-items: center;\n height: 36px;\n margin: 2px 0;\n }\n .mmp-dropdown__button.icon {\n height: 40px;\n margin: 0;\n }\n .mmp-dropdown__button > div {\n display: flex;\n flex: 1;\n justify-content: space-between;\n align-items: center;\n height: 36px;\n max-width: 100%;\n }\n .mmp-dropdown__label {\n text-align: left;\n text-transform: none;\n }\n .mmp-dropdown__icon {\n height: 24px;\n width: 24px;\n min-width: 24px;\n }\n paper-item > *:nth-child(2) {\n margin-left: 4px;\n }\n paper-menu-button[focused] mmp-button iron-icon {\n color: var(--mmp-accent-color);\n transform: rotate(180deg);\n }\n paper-menu-button[focused] paper-icon-button {\n color: var(--mmp-accent-color);\n transform: rotate(180deg);\n }\n paper-menu-button[focused] paper-icon-button[focused] {\n color: var(--mmp-text-color);\n transform: rotate(0deg);\n }\n "]);return $=function(){return a},a}function _(){const a=sa(["",""]);return _=function(){return a},a}function aa(){const a=sa([""]);return aa=function(){return a},a}function ba(){const a=sa(["\n \n ","\n ","\n "]);return ba=function(){return a},a}function ca(){const a=sa(["\n \n \n \n ","\n \n \n
\n \n "]);return ca=function(){return a},a}function da(){const a=sa(["\n \n \n "]);return da=function(){return a},a}function ea(){const a=sa(["\n \n ","\n \n ","\n \n \n "]);return ea=function(){return a},a}function fa(){const a=sa(["\n .ellipsis {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .label {\n margin: 0 8px;\n }\n paper-icon-button {\n transition: color .25s;\n }\n paper-icon-button[color] {\n color: var(--mmp-accent-color) !important;\n opacity: 1 !important;\n }\n paper-icon-button[inactive] {\n opacity: .5;\n }\n"]);return fa=function(){return a},a}function ga(){const a=sa(["\n .mmp-group-list {\n display: flex;\n flex-direction: column;\n margin-left: 8px;\n }\n .mmp-group-list__title {\n font-weight: 500;\n letter-spacing: .1em;\n margin: 8px 0 4px;\n text-transform: uppercase;\n }\n .mmp-group-list__buttons {\n display: flex;\n }\n .mmp-group-list__button {\n margin: 8px 8px 0 0;\n min-width: 0;\n text-transform: uppercase;\n text-align: center;\n width: 50%;\n --mdc-theme-primary: transparent;\n background: rgba(255,255,255,0.25);\n }\n "]);return ga=function(){return a},a}function ha(){const a=sa([""]);return ha=function(){return a},a}function ia(){const a=sa(["Leave"]);return ia=function(){return a},a}function ja(){const a=sa(["Ungroup"]);return ja=function(){return a},a}function ka(){const a=sa(["\n "]);return ka=function(){return a},a}function la(){const a=sa(["\n \n
Group speakers\n ","\n
\n \n ","\n \n \n Group all\n \n
\n
\n "]);return la=function(){return a},a}function ma(){const a=sa(["\n :host {\n position: relative;\n box-sizing: border-box;\n margin: 4px;\n min-width: 0;\n overflow: hidden;\n transition: background .5s;\n }\n :host([raised]) {\n background: rgba(255,255,255,0.25);\n min-height: 36px;\n box-shadow:\n 0px 3px 1px -2px rgba(0, 0, 0, 0.2),\n 0px 2px 2px 0px rgba(0, 0, 0, 0.14),\n 0px 1px 5px 0px rgba(0,0,0,.12);\n }\n :host([color]) {\n background: var(--mmp-active-color);\n transition: background .25s;\n opacity: 1;\n }\n :host([faded]) {\n opacity: .75;\n }\n .container {\n height: 100%;\n width: 100%;\n }\n .slot-container {\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 8px;\n width: auto;\n }\n paper-ripple {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n }\n "]);return ma=function(){return a},a}function na(){const a=sa(["\n \n "]);return na=function(){return a},a}function oa(){const a=sa(["\n paper-checkbox {\n padding: 8px 0;\n }\n paper-checkbox > span {\n font-weight: 600;\n }\n\n ha-card[artwork*='cover'][has-artwork] paper-checkbox[disabled] {\n --paper-checkbox-checkmark-color: rgba(0,0,0,.5);\n }\n ha-card[artwork*='cover'][has-artwork] paper-checkbox {\n --paper-checkbox-unchecked-color: #FFFFFF;\n --paper-checkbox-label-color: #FFFFFF;\n }\n "]);return oa=function(){return a},a}function pa(){const a=sa(["(master)"]);return pa=function(){return a},a}function qa(){const a=sa(["\n \n ","\n ","\n \n "]);return qa=function(){return a},a}function ra(){const a=sa(["\n :host {\n overflow: visible !important;\n display: block;\n --mmp-accent-color: var(--mini-media-player-accent-color, var(--accent-color, #f39c12));\n --mmp-base-color: var(--mini-media-player-base-color, var(--primary-text-color, #000));\n --mmp-overlay-color: var(--mini-media-player-overlay-color, rgba(0,0,0,0.5));\n --mmp-overlay-base-color: var(--mini-media-player-overlay-base-color, #fff);\n --mmp-overlay-accent-color: var(--mini-media-player-overlay-accent-color, --mmp-accent-color);\n --mmp-text-color: var(--mini-media-player-base-color, --primary-text-color);\n --mmp-media-cover-info-color: var(--mini-media-player-media-cover-info-color, --mmp-text-color);\n --mmp-text-color-inverted: var(--disabled-text-color);\n --mmp-active-color: var(--mmp-accent-color);\n --mmp-icon-color: var(--mini-media-player-base-color, var(--paper-item-icon-color, #44739e));\n --mmp-info-opacity: 1;\n --mdc-theme-primary: var(--mmp-text-color);\n --mdc-theme-on-primary: var(--mmp-text-color);\n --paper-checkbox-unchecked-color: var(--mmp-text-color);\n --paper-checkbox-label-color: var(--mmp-text-color);\n color: var(--mmp-text-color);\n }\n ha-card.--bg {\n --mmp-info-opacity: .75;\n }\n ha-card.--has-artwork[artwork*='cover'] {\n --mmp-accent-color: var(--mini-media-player-overlay-accent-color, var(--mini-media-player-accent-color, var(--accent-color, #f39c12)));\n --mmp-text-color: var(--mmp-overlay-base-color);\n --mmp-text-color-inverted: #000;\n --mmp-active-color: rgba(255,255,255,.5);\n --mmp-icon-color: var(--mmp-text-color);\n --mmp-info-opacity: .75;\n --paper-slider-container-color: var(--mini-media-player-overlay-color, rgba(255,255,255,.75));\n --mdc-theme-primary: var(--mmp-text-color);\n --mdc-theme-on-primary: var(--mmp-text-color);\n --paper-checkbox-unchecked-color: var(--mmp-text-color);\n --paper-checkbox-label-color: var(--mmp-text-color);\n color: var(--mmp-text-color);\n }\n ha-card {\n cursor: default;\n display: flex;\n background: transparent;\n overflow: hidden;\n padding: 0;\n position: relative;\n color: inherit;\n }\n ha-card.--group {\n box-shadow: none;\n }\n ha-card.--more-info {\n cursor: pointer;\n }\n ha-card.--collapse {\n overflow: visible;\n }\n .mmp__bg, .mmp__player, .mmp__container {\n border-radius: var(--ha-card-border-radius, 0);\n -webkit-transform: translateZ(0);\n transform: translateZ(0);\n }\n .mmp__container {\n overflow: hidden;\n height: 100%;\n width: 100%;\n position: absolute;\n pointer-events: none;\n }\n ha-card:before {\n content: '';\n padding-top: 0px;\n transition: padding-top .5s cubic-bezier(.21,.61,.35,1);\n will-change: padding-top;\n }\n ha-card.--initial .entity__artwork,\n ha-card.--initial .entity__icon {\n animation-duration: .001s;\n }\n ha-card.--initial:before,\n ha-card.--initial .mmp-player {\n transition: none;\n }\n header {\n display: none;\n }\n ha-card[artwork='full-cover'].--has-artwork:before {\n padding-top: 56%;\n }\n ha-card[artwork='full-cover'].--has-artwork[content='music']:before,\n ha-card[artwork='full-cover-fit'].--has-artwork:before {\n padding-top: 100%;\n }\n .mmp__bg {\n background: var(--ha-card-background, var(--paper-card-background-color, white));\n position: absolute;\n top: 0; right: 0; bottom: 0; left: 0;\n overflow: hidden;\n -webkit-transform: translateZ(0);\n transform: translateZ(0);\n }\n ha-card.--group .mmp__bg {\n background: transparent;\n }\n .cover,\n .cover:before {\n display: block;\n opacity: 0;\n position: absolute;\n top: 0; right: 0; bottom: 0; left: 0;\n transition: opacity .75s cubic-bezier(.21,.61,.35,1);\n will-change: opacity;\n }\n .cover {\n animation: fade-in .5s cubic-bezier(.21,.61,.35,1);\n background-size: cover;\n background-repeat: no-repeat;\n background-position: center center;\n }\n .cover:before {\n background: var(--mmp-overlay-color);\n content: '';\n }\n ha-card[artwork*='full-cover'].--has-artwork .mmp-player {\n background: linear-gradient(to top, var(--mmp-overlay-color) 25%, transparent 100%);\n border-bottom-left-radius: var(--ha-card-border-radius, 0);\n border-bottom-right-radius: var(--ha-card-border-radius, 0);\n }\n ha-card.--has-artwork .cover,\n ha-card.--has-artwork[artwork='cover'] .cover:before,\n ha-card.--bg .cover {\n opacity: .999;\n }\n ha-card[artwork='default'] .cover {\n display: none;\n }\n ha-card.--bg .cover {\n display: block;\n }\n ha-card[artwork='full-cover-fit'].--has-artwork .cover {\n background-color: black;\n background-size: contain;\n }\n .mmp-player {\n align-self: flex-end;\n box-sizing: border-box;\n position: relative;\n padding: 16px;\n transition: padding .25s ease-out;\n width: 100%;\n will-change: padding;\n }\n ha-card.--group .mmp-player {\n padding: 2px 0;\n }\n .flex {\n display: flex;\n display: -ms-flexbox;\n display: -webkit-flex;\n flex-direction: row;\n }\n .mmp-player__core {\n position: relative;\n }\n .entity__info {\n justify-content: center;\n display: flex;\n flex-direction: column;\n margin-left: 8px;\n position: relative;\n overflow: hidden;\n user-select: none;\n }\n ha-card.--rtl .entity__info {\n margin-left: auto;\n margin-right: 8px;\n }\n ha-card[content='movie'] .attr__media_season,\n ha-card[content='movie'] .attr__media_episode {\n display: none;\n }\n .entity__icon {\n color: var(--mmp-icon-color);\n }\n .entity__artwork, .entity__icon {\n animation: fade-in .25s ease-out;\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n border-radius: 100%;\n height: 40px;\n width: 40px;\n min-width: 40px;\n line-height: 40px;\n margin-right: 8px;\n position: relative;\n text-align: center;\n will-change: border-color;\n transition: border-color .25s ease-out;\n }\n ha-card.--rtl .entity__artwork,\n ha-card.--rtl .entity__icon {\n margin-right: auto;\n }\n .entity__artwork[border] {\n border: 2px solid var(--primary-text-color);\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n -webkit-box-sizing: border-box;\n }\n .entity__artwork[border][state='playing'] {\n border-color: var(--mmp-accent-color);\n }\n .entity__info__name,\n .entity__info__media[short] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .entity__info__name {\n line-height: 20px;\n color: var(--mmp-text-color);\n }\n .entity__info__media {\n color: var(--secondary-text-color);\n max-height: 6em;\n word-break: break-word;\n opacity: var(--mmp-info-opacity);\n transition: color .5s;\n }\n .entity__info__media[short] {\n max-height: 20px;\n overflow: hidden;\n }\n .attr__app_name {\n display: none;\n }\n .attr__app_name:first-child,\n .attr__app_name:first-of-type {\n display: inline;\n }\n .mmp-player__core[inactive] .entity__info__media {\n color: var(--mmp-text-color);\n max-width: 200px;\n opacity: .5;\n }\n .entity__info__media[short-scroll] {\n max-height: 20px;\n white-space: nowrap;\n }\n .entity__info__media[scroll] > span {\n visibility: hidden;\n }\n .entity__info__media[scroll] > div {\n animation: move linear infinite;\n }\n .entity__info__media[scroll] .marquee {\n animation: slide linear infinite;\n }\n .entity__info__media[scroll] .marquee,\n .entity__info__media[scroll] > div {\n animation-duration: inherit;\n visibility: visible;\n }\n .entity__info__media[scroll] {\n animation-duration: 10s;\n mask-image: linear-gradient(to right, transparent 0%, black 5%, black 95%, transparent 100%);\n -webkit-mask-image: linear-gradient(to right, transparent 0%, black 5%, black 95%, transparent 100%);\n }\n .marquee {\n visibility: hidden;\n position: absolute;\n white-space: nowrap;\n }\n ha-card[artwork*='cover'].--has-artwork .entity__info__media,\n ha-card.--bg .entity__info__media {\n color: var(--mmp-media-cover-info-color);\n }\n .entity__info__media span:before {\n content: ' - ';\n }\n .entity__info__media span:first-of-type:before {\n content: '';\n }\n .entity__info__media span:empty {\n display: none;\n }\n .mmp-player__adds {\n margin-left: 48px;\n position: relative;\n }\n ha-card.--rtl .mmp-player__adds {\n margin-left: auto;\n margin-right: 48px;\n }\n .mmp-player__adds > *:nth-child(2) {\n margin-top: 0px;\n }\n mmp-powerstrip {\n flex: 1;\n justify-content: flex-end;\n margin-right: 0;\n margin-left: auto;\n width: auto;\n max-width: 100%;\n }\n mmp-media-controls {\n flex-wrap: wrap;\n justify-content: center;\n }\n ha-card.--flow mmp-powerstrip {\n justify-content: space-between;\n margin-left: auto;\n }\n ha-card.--flow.--rtl mmp-powerstrip {\n margin-right: auto;\n }\n ha-card.--flow .entity__info {\n display: none;\n }\n ha-card.--responsive .mmp-player__adds {\n margin-left: 0;\n }\n ha-card.--responsive.--rtl .mmp-player__adds {\n margin-right: 0;\n }\n ha-card.--responsive .mmp-player__adds > mmp-media-controls {\n padding: 0;\n }\n ha-card.--runtime .mmp-player {\n padding-bottom: calc(16px + 8px);\n }\n ha-card.--runtime.--group .mmp-player {\n padding-bottom: calc(16px + 8px);\n }\n .mmp-player div:empty {\n display: none;\n }\n @keyframes slide {\n 100% { transform: translateX(-100%); }\n }\n @keyframes move {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n @keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n"]);return ra=function(){return a},a}function sa(a,b){return b||(b=a.slice(0)),Object.freeze(Object.defineProperties(a,{raw:{value:Object.freeze(b)}}))}function ta(a){for(var b=1;ba.parentNode.removeChild(a))}function va(a,b){let c=2"function"==typeof a&&Ia.has(a),Ka=window.customElements!==void 0&&window.customElements.polyfillWrapFlushCallback!==void 0,La=function(a,b){for(let c=2"),Qa=new RegExp("".concat(Oa,"|").concat(Pa)),Ra="$lit$";class Sa{constructor(a,b){this.parts=[],this.element=b;const c=[],d=[],e=document.createTreeWalker(b.content,133,null,!1);let f=0,g=-1,h=0;for(const i=a.strings,j=a.values.length;h{const c=a.length-b.length;return 0<=c&&a.slice(c)===b},Ua=a=>-1!==a.index,Va=()=>document.createComment(""),Wa=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;class Xa{constructor(a,b,c){this.__parts=[],this.template=a,this.processor=b,this.options=c}update(a){let b=0;for(const c of this.__parts)void 0!==c&&c.setValue(a[b]),b++;for(const b of this.__parts)void 0!==b&&b.commit()}_clone(){const a=Ka?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),b=[],c=this.template.parts,d=document.createTreeWalker(a,133,null,!1);let e,f=0,g=0,h=d.nextNode();for(;f",e+1);const f=Wa.exec(a);b+=null===f?a+(c?Oa:Pa):a.substr(0,f.index)+f[1]+f[2]+Ra+f[3]+Oa}return b+=this.strings[a],b}getTemplateElement(){const a=document.createElement("template");return a.innerHTML=this.getHTML(),a}}const Za=a=>null===a||"object"!=typeof a&&"function"!=typeof a,$a=a=>Array.isArray(a)||!!(a&&a[Symbol.iterator]);class _a{constructor(a,b,c){this.dirty=!0,this.element=a,this.name=b,this.strings=c,this.parts=[];for(let d=0;dthis.handleEvent(a)}setValue(a){this.__pendingValue=a}commit(){for(;Ja(this.__pendingValue);){const a=this.__pendingValue;this.__pendingValue=Ma,a(this)}if(this.__pendingValue===Ma)return;const a=this.__pendingValue,b=this.value,c=null==a||null!=b&&(a.capture!==b.capture||a.once!==b.once||a.passive!==b.passive);c&&this.element.removeEventListener(this.eventName,this.__boundHandleEvent,this.__options),null!=a&&(null==b||c)&&(this.__options=hb(a),this.element.addEventListener(this.eventName,this.__boundHandleEvent,this.__options)),this.value=a,this.__pendingValue=Ma}handleEvent(a){"function"==typeof this.value?this.value.call(this.eventContext||this.element,a):this.value.handleEvent(a)}}const hb=a=>a&&(fb?{capture:a.capture,passive:a.passive,once:a.once}:a.capture);const ib=new class{handleAttributeExpressions(a,b,c,d){const e=b[0];if("."===e){const d=new db(a,b.slice(1),c);return d.parts}if("@"===e)return[new gb(a,b.slice(1),d.eventContext)];if("?"===e)return[new cb(a,b.slice(1),c)];const f=new _a(a,b,c);return f.parts}handleTextExpression(a){return new bb(a)}},jb=new Map,kb=new WeakMap,lb=(a,b,c)=>{let d=kb.get(b);d===void 0&&(La(b,b.firstChild),kb.set(b,d=new bb(Object.assign({templateFactory:sa},c))),d.appendInto(b)),d.setValue(a),d.commit()};(window.litHtmlVersions||(window.litHtmlVersions=[])).push("1.0.0");const mb=function(a){for(var b=arguments.length,c=Array(1{let b=11===a.nodeType?0:1;for(const c=document.createTreeWalker(a,nb,null,!1);c.nextNode();)b++;return b},pb=function(a){let b=1"".concat(a,"--").concat(b);let rb=!0;"undefined"==typeof window.ShadyCSS?rb=!1:"undefined"==typeof window.ShadyCSS.prepareTemplateDom&&(console.warn("Incompatible ShadyCSS version detected. Please update to at least @webcomponents/webcomponentsjs@2.0.2 and @webcomponents/shadycss@1.3.1."),rb=!1);const sb=a=>b=>{const c=qb(b.type,a);let d=jb.get(c);void 0===d&&(d={stringsArray:new WeakMap,keyString:new Map},jb.set(c,d));let e=d.stringsArray.get(b.strings);if(void 0!==e)return e;const f=b.strings.join(Oa);if(e=d.keyString.get(f),void 0===e){const c=b.getTemplateElement();rb&&window.ShadyCSS.prepareTemplateDom(c,a),e=new Sa(b,c),d.keyString.set(f,e)}return d.stringsArray.set(b.strings,e),e},tb=["html","svg"],ub=a=>{tb.forEach(b=>{const c=jb.get(qb(b,a));c!==void 0&&c.keyString.forEach(a=>{const b=a.element.content,c=new Set;Array.from(b.querySelectorAll("style")).forEach(a=>{c.add(a)}),ua(a,c)})})},vb=new Set,wb=(a,b,c)=>{vb.add(c);const d=a.querySelectorAll("style"),e=d.length;if(0===e)return void window.ShadyCSS.prepareTemplateStyles(b.element,c);const f=document.createElement("style");for(let g=0;g{const d=c.scopeName,e=kb.has(b),f=rb&&11===b.nodeType&&!!b.host&&a instanceof Ya,g=f&&!vb.has(d),h=g?document.createDocumentFragment():b;if(lb(a,h,Object.assign({templateFactory:sb(d)},c)),g){const a=kb.get(h);kb.delete(h),a.value instanceof Xa&&wb(h,a.value.template,d),La(b,b.firstChild),b.appendChild(h),kb.set(b,a)}!e&&f&&window.ShadyCSS.styleElement(b.host)};window.JSCompiler_renameProperty=a=>a;const yb={toAttribute(a,b){return b===Boolean?a?"":null:b===Object||b===Array?null==a?a:JSON.stringify(a):a},fromAttribute(a,b){return b===Boolean?null!==a:b===Number?null===a?null:+a:b===Object||b===Array?JSON.parse(a):a}},zb=(a,b)=>b!==a&&(b===b||a===a),Ab={attribute:!0,type:String,converter:yb,reflect:!1,hasChanged:zb},Bb=Promise.resolve(!0),Cb=1,Db=4,Eb=8,Fb=16,Gb=32;class Hb extends HTMLElement{constructor(){super(),this._updateState=0,this._instanceProperties=void 0,this._updatePromise=Bb,this._hasConnectedResolver=void 0,this._changedProperties=new Map,this._reflectingProperties=void 0,this.initialize()}static get observedAttributes(){this.finalize();const a=[];return this._classProperties.forEach((b,c)=>{const d=this._attributeNameForProperty(c,b);void 0!==d&&(this._attributeToPropertyMap.set(d,c),a.push(d))}),a}static _ensureClassProperties(){if(!this.hasOwnProperty(JSCompiler_renameProperty("_classProperties",this))){this._classProperties=new Map;const a=Object.getPrototypeOf(this)._classProperties;a!==void 0&&a.forEach((a,b)=>this._classProperties.set(b,a))}}static createProperty(a){let b=1{if(this.hasOwnProperty(b)){const a=this[b];delete this[b],this._instanceProperties||(this._instanceProperties=new Map),this._instanceProperties.set(b,a)}})}_applyInstanceProperties(){this._instanceProperties.forEach((a,b)=>this[b]=a),this._instanceProperties=void 0}connectedCallback(){this._updateState|=Gb,this._hasConnectedResolver&&(this._hasConnectedResolver(),this._hasConnectedResolver=void 0)}disconnectedCallback(){}attributeChangedCallback(a,b,c){b!==c&&this._attributeToProperty(a,c)}_propertyToAttribute(a,b){let c=2{b=a,c=d});try{yield d}catch(a){}a._hasConnected||(yield new Promise(b=>a._hasConnectedResolver=b));try{const b=a.performUpdate();null!=b&&(yield b)}catch(a){c(a)}b(!a._hasRequestedUpdate)})()}get _hasConnected(){return this._updateState&Gb}get _hasRequestedUpdate(){return this._updateState&Db}get hasUpdated(){return this._updateState&Cb}performUpdate(){this._instanceProperties&&this._applyInstanceProperties();let a=!1;const b=this._changedProperties;try{a=this.shouldUpdate(b),a&&this.update(b)}catch(b){throw a=!1,b}finally{this._markUpdated()}a&&(!(this._updateState&Cb)&&(this._updateState|=Cb,this.firstUpdated(b)),this.updated(b))}_markUpdated(){this._changedProperties=new Map,this._updateState&=~Db}get updateComplete(){return this._updatePromise}shouldUpdate(a){return!0}update(a){this._reflectingProperties!==void 0&&0this._propertyToAttribute(b,this[b],a)),this._reflectingProperties=void 0)}updated(a){}firstUpdated(a){}}Hb.finalized=!0;const Ib="adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Jb=Symbol();class Kb{constructor(a,b){if(b!==Jb)throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=a}get styleSheet(){return void 0===this._styleSheet&&(Ib?(this._styleSheet=new CSSStyleSheet,this._styleSheet.replaceSync(this.cssText)):this._styleSheet=null),this._styleSheet}toString(){return this.cssText}}const Lb=a=>{if(a instanceof Kb)return a.cssText;if("number"==typeof a)return a;throw new Error("Value passed to 'css' function must be a 'css' function result: ".concat(a,". Use 'unsafeCSS' to pass non-literal values, but\n take care to ensure page security."))},Mb=function(a){for(var b=arguments.length,c=Array(1b+Lb(c)+a[d+1],a[0]);return new Kb(e,Jb)};(window.litElementVersions||(window.litElementVersions=[])).push("2.2.0");const Nb=a=>a.flat?a.flat(1/0):xa(a);class Ob extends Hb{static finalize(){super.finalize(),this._styles=this.hasOwnProperty(JSCompiler_renameProperty("styles",this))?this._getUniqueStyles():this._styles||[]}static _getUniqueStyles(){const a=this.styles,b=[];if(Array.isArray(a)){const c=Nb(a),d=c.reduceRight((a,b)=>(a.add(b),a),new Set);d.forEach(a=>b.unshift(a))}else a&&b.push(a);return b}initialize(){super.initialize(),this.renderRoot=this.createRenderRoot(),window.ShadowRoot&&this.renderRoot instanceof window.ShadowRoot&&this.adoptStyles()}createRenderRoot(){return this.attachShadow({mode:"open"})}adoptStyles(){const a=this.constructor._styles;0===a.length||(window.ShadyCSS===void 0||window.ShadyCSS.nativeShadow?Ib?this.renderRoot.adoptedStyleSheets=a.map(a=>a.styleSheet):this._needsShimAdoptedStyleSheets=!0:window.ShadyCSS.ScopingShim.prepareAdoptedCssText(a.map(a=>a.cssText),this.localName))}connectedCallback(){super.connectedCallback(),this.hasUpdated&&window.ShadyCSS!==void 0&&window.ShadyCSS.styleElement(this)}update(a){super.update(a);const b=this.render();b instanceof Ya&&this.constructor.render(b,this.renderRoot,{scopeName:this.localName,eventContext:this}),this._needsShimAdoptedStyleSheets&&(this._needsShimAdoptedStyleSheets=!1,this.constructor._styles.forEach(a=>{const b=document.createElement("style");b.textContent=a.cssText,this.renderRoot.appendChild(b)}))}render(){}}Ob.finalized=!0,Ob.render=xb;const Pb=new WeakMap,Qb=(a=>function(){const b=a(...arguments);return Ia.set(b,!0),b})(a=>b=>{if(!(b instanceof ab)||b instanceof eb||"class"!==b.committer.name||1ta({text:this.attr[a.attr],prefix:""},a)).filter(a=>a.text)}get hasProgress(){return!this.config.hide.progress&&!this.idle&&jc.every(a=>a in this.attr)}get progress(){return this.position+(Date.now()-new Date(this.updatedAt).getTime())/1e3}get idleView(){const a=this.config.idle_view;return!!(a.when_idle&&this.isIdle||a.when_standby&&this.isStandby||a.when_paused&&this.isPaused)||!!(this.updatedAt&&a.after&&!this.isPlaying)&&this.checkIdleAfter(a.after)}get trackIdle(){return this.active&&!this.isPlaying&&this.updatedAt&&this.config.idle_view&&this.config.idle_view.after}checkIdleAfter(a){const b=(Date.now()-new Date(this.updatedAt).getTime())/1e3;return this.idle=b>60*a,this.active=this.isActive,this.idle}get supportsShuffle(){return"undefined"!=typeof this.attr.shuffle}get supportsMute(){return"undefined"!=typeof this.attr.is_volume_muted}getAttribute(a){return this.attr[a]||""}fetchThumbnail(){var a=this;return wa(function*(){try{const b=yield a.hass.callWS({type:"media_player_thumbnail",entity_id:a.config.entity}),c=b.content_type,d=b.content;return"url(data:".concat(c,";base64,").concat(d,")")}catch(a){return console.error("mini-media-player: Failed fetching thumbnail"),!1}})()}toggle(a){return this.config.toggle_power?this.callService(a,"toggle"):this.isOff?this.callService(a,"turn_on"):void this.callService(a,"turn_off")}toggleMute(a){this.callService(a,"volume_mute",{is_volume_muted:!this.muted})}toggleShuffle(a){this.callService(a,"shuffle_set",{shuffle:!this.shuffle})}setSource(a,b){this.callService(a,"select_source",{source:b})}setMedia(a,b){this.callService(a,"play_media",ta({},b))}playPause(a){this.callService(a,"media_play_pause")}setSoundMode(a,b){this.callService(a,"select_sound_mode",{sound_mode:b})}next(a){this.callService(a,"media_next_track")}prev(a){this.callService(a,"media_previous_track")}stop(a){this.callService(a,"media_stop")}volumeUp(a){this.callService(a,"volume_up")}volumeDown(a){this.callService(a,"volume_down")}seek(a,b){this.callService(a,"media_seek",{seek_position:b})}setVolume(a,b){this.config.speaker_group.sync_volume?this.group.forEach(c=>{const d=this.config.speaker_group.entities.find(a=>a.entity_id===c)||{};let e=b;d.volume_offset&&(e+=d.volume_offset/100,1e&&(e=0)),this.callService(a,"volume_set",{entity_id:c,volume_level:e})}):this.callService(a,"volume_set",{entity_id:this.config.entity,volume_level:b})}handleGroupChange(a,b,c){const d=this.config.speaker_group.platform,e={entity_id:b};if(c){if(e.master=this.config.entity,"sonos"===d)return this.callService(a,"join",e,d);this.callService(a,"".concat(d,"_JOIN"),e)}else{if("sonos"===d)return this.callService(a,"unjoin",e,d);this.callService(a,"".concat(d,"_UNJOIN"),e)}}toggleScript(a,b){let c=2a.stopPropagation(),this.handleClick,this.item.name,this.master?mb(pa()):"")}handleClick(a){a.stopPropagation(),this.dispatchEvent(new CustomEvent("change",{detail:{entity:this.item.entity_id,checked:!this.checked}}))}static get styles(){return Mb(oa())}}customElements.define("mmp-group-item",nc);class oc extends Ob{render(){return mb(na())}static get styles(){return Mb(ma())}}customElements.define("mmp-button",oc);class pc extends Ob{static get properties(){return{entities:{},player:{},visible:Boolean}}get group(){return this.player.group}get master(){return this.player.master}get isMaster(){return this.player.isMaster}handleGroupChange(a){const b=a.detail,c=b.entity,d=b.checked;this.player.handleGroupChange(a,c,d)}render(){let a=0mb(ka(),this.handleGroupChange,a,a.entity_id===this.player.id||b.includes(a.entity_id),a.entity_id===this.player.id||c!==this.player.id,a.entity_id===c)),2>b.length,a=>this.player.handleGroupChange(a,d?b:this.player.entity_id,!1),d?mb(ja()):mb(ia()),!d,a=>this.player.handleGroupChange(a,this.entities.map(a=>a.entity_id),!0)):mb(ha())}static get styles(){return Mb(ga())}}customElements.define("mmp-group-list",pc);const qc=Mb(fa());class rc extends Ob{static get properties(){return{items:[],label:String,selected:String}}get selectedId(){return this.items.map(a=>a.id).indexOf(this.selected)}onChange(a){this.dispatchEvent(new CustomEvent("change",{detail:a}))}render(){return mb(ea(),"right","top",44,a=>a.stopPropagation(),this.icon?mb(da(),hc.DROPDOWN):mb(ca(),this.selected||this.label,hc.DROPDOWN),this.selectedId,this.items.map(a=>mb(ba(),a.id||a.name,()=>this.onChange(a),a.icon?mb(aa(),a.icon):"",a.name?mb(_(),a.name):"")))}static get styles(){return[qc,Mb($())]}}customElements.define("mmp-dropdown",rc);class sc extends Ob{static get properties(){return{player:{},shortcuts:{}}}get buttons(){return this.shortcuts.buttons}get list(){return this.shortcuts.list}get show(){return!this.shortcuts.hide_when_off||this.player.active}get active(){return this.player.getAttribute(this.shortcuts.attribute)}get height(){return this.shortcuts.column_height||36}render(){if(!this.show)return mb(Z());const a=this.active,b=this.list?mb(Y(),this.handleShortcut,this.list,this.shortcuts.label,a):"",c=this.buttons?mb(X(),this.buttons.map(b=>mb(W(),"min-height: ".concat(this.height,"px;"),this.shortcuts.columns,b.id===a,a=>this.handleShortcut(a,b),this.shortcuts.align_text,b.icon?mb(V(),b.icon):"",b.name?mb(U(),b.name):""))):"";return mb(T(),c,b)}handleShortcut(a,b){const c=b||a.detail,d=c.type,e=c.id,f=c.data;if("source"===d)return this.player.setSource(a,e);if("service"===d)return this.player.toggleService(a,e,f);if("script"===d)return this.player.toggleScript(a,e,f);if("sound_mode"===d)return this.player.setSoundMode(a,e);this.player.setMedia(a,{media_content_type:d,media_content_id:e})}static get styles(){return[qc,Mb(S())]}}customElements.define("mmp-shortcuts",sc);const tc=function(a,b){let c=2a.stopPropagation(),this.handleTts)}handleTts(a){const b=this.config,c=this.message,d={message:c,entity_id:b.entity_id||this.entity};b.language&&(d.language=b.language),"alexa"===b.platform?this.hass.callService("notify","alexa_media",{message:c,data:{type:b.type||"tts"},target:d.entity_id}):"sonos"===b.platform?this.hass.callService("script","sonos_say",{sonos_entity:d.entity_id,volume:b.volume||.5,message:c}):"webos"===b.platform?this.hass.callService("notify",d.entity_id.split(".").slice(-1)[0],{message:c}):"ga"===b.platform?this.hass.callService("notify","ga_broadcast",{message:c}):this.hass.callService("tts","".concat(b.platform,"_say"),d),a.stopPropagation(),this.reset()}reset(){this.input.value=""}static get styles(){return Mb(Q())}}customElements.define("mmp-tts",uc);var vc=a=>{let b=parseInt(a%60,10),c=parseInt(a/60%60,10),d=parseInt(a/3600%24,10);return d=10>d?"0".concat(d):d,c=10>c?"0".concat(c):c,b=10>b?"0".concat(b):b,"".concat("00"===d?"":"".concat(d,":")).concat(c,":").concat(b)};class wc extends Ob{static get properties(){return{_player:{},showTime:Boolean,progress:Number,duration:Number,tracker:{},track:Boolean}}set player(a){this._player=a,this.hasProgress&&this.trackProgress()}get duration(){return this.player.mediaDuration}get player(){return this._player}get hasProgress(){return this.player.hasProgress}render(){return this.player.active&&this.hasProgress?mb(P(),this.handleSeek,!this.player.isPlaying,this.showTime?mb(O(),vc(this.progress),vc(this.duration)):"",this.progress,this.duration):mb(N())}trackProgress(){this.progress=this.player.progress,this.tracker||(this.tracker=setInterval(()=>this.trackProgress(),1e3)),this.player.isPlaying||(clearInterval(this.tracker),this.tracker=null)}handleSeek(a){const b=this.duration,c=a.offsetX/a.target.offsetWidth*b;this.player.seek(a,c)}disconnectedCallback(){clearInterval(this.tracker)}static get styles(){return Mb(M())}}customElements.define("mmp-progress",wc);class xc extends Ob{static get properties(){return{player:{},selected:String,icon:Boolean}}get source(){return this.player.source}get sources(){return this.player.sources.map(a=>({name:a,id:a,type:"source"}))}render(){return mb(L(),this.handleSource,this.sources,this.source,this.selected||this.source,this.icon)}handleSource(a){const b=a.detail.id;this.player.setSource(a,b),this.selected=b}static get styles(){return Mb(K())}}customElements.define("mmp-source-menu",xc);class yc extends Ob{static get properties(){return{player:{},selected:String,icon:Boolean}}get mode(){return this.player.soundMode}get modes(){return this.player.soundModes.map(a=>({name:a,id:a,type:"soundMode"}))}render(){return mb(J(),this.handleChange,this.modes,this.mode,this.selected||this.mode,this.icon)}handleChange(a){const b=a.detail.id;this.player.setSoundMode(a,b),this.selected=b}static get styles(){return Mb(I())}}customElements.define("mmp-sound-menu",yc);class zc extends Ob{static get properties(){return{player:{},config:{},break:Boolean}}get showShuffle(){return!this.config.hide.shuffle&&this.player.supportsShuffle}get maxVol(){return this.config.max_volume||100}get minVol(){return this.config.min_volume||0}render(){const a=this.config.hide;return mb(H(),a.volume?mb(G()):this.renderVolControls(this.player.muted),this.showShuffle?mb(F(),a=>this.player.toggleShuffle(a),hc.SHUFFLE,this.player.shuffle):mb(E()),a.controls?mb(C()):mb(D(),this.config.flow||this.break,a=>this.player.prev(a),hc.PREV,a=>this.player.playPause(a),hc.PLAY[this.player.isPlaying],a=>this.player.next(a),hc.NEXT))}renderVolControls(a){return this.config.volume_stateless?this.renderVolButtons(a):this.renderVolSlider(a)}renderVolSlider(a){return mb(B(),this.renderMuteButton(a),this.handleVolumeChange,a=>a.stopPropagation(),a,this.minVol,this.maxVol,100*this.player.vol,"ltr")}renderVolButtons(a){return mb(A(),this.renderMuteButton(a),a=>this.player.volumeDown(a),hc.VOL_DOWN,a=>this.player.volumeUp(a),hc.VOL_UP)}renderMuteButton(a){if(!this.config.hide.mute)switch(this.config.replace_mute){case"play":return mb(z(),a=>this.player.playPause(a),hc.PLAY[this.player.isPlaying]);case"stop":return mb(y(),a=>this.player.stop(a),hc.STOP);case"next":return mb(x(),a=>this.player.next(a),hc.NEXT);default:return this.player.supportsMute?mb(w(),a=>this.player.toggleMute(a),hc.MUTE[a]):void 0;}}handleVolumeChange(a){const b=parseFloat(a.target.value)/100;this.player.setVolume(a,b)}static get styles(){return[qc,Mb(v())]}}customElements.define("mmp-media-controls",zc);class Ac extends Ob{static get properties(){return{hass:{},player:{},config:{},groupVisible:Boolean,idle:Boolean}}get showGroupButton(){return this.config.speaker_group.entities}get showPowerButton(){return!this.config.hide.power}get powerColor(){return this.player.active&&!this.config.hide.power_state}get sourceSize(){return"icon"===this.config.source||this.config.collapse||this.idle}get soundSize(){return"icon"===this.config.sound_mode||this.config.collapse||this.idle}get hasSource(){return 0this.player.toggle(a),this.powerColor):"")}handleGroupClick(a){a.stopPropagation(),this.dispatchEvent(new CustomEvent("toggleGroupList"))}get renderIdleView(){return this.player.isPaused?mb(n(),hc.PLAY[this.player.isPlaying],a=>this.player.playPause(a)):mb(m(),tc(this.hass,"state.media_player.idle","Idle"))}static get styles(){return[qc,Mb(l())]}}customElements.define("mmp-powerstrip",Ac),customElements.get("ha-slider")||customElements.define("ha-slider",class extends customElements.get("paper-slider"){});class Bc extends Ob{constructor(){super(),this._overflow=!1,this.initial=!0,this.picture=!1,this.thumbnail=!1,this.edit=!1,this.rtl=!1}static get properties(){return{_hass:{},config:{},entity:{},player:{},_overflow:Boolean,break:Boolean,initial:Boolean,picture:String,thumbnail:String,edit:Boolean,rtl:Boolean,idle:Boolean}}static get styles(){return mc}set hass(a){if(a){const b=a.states[this.config.entity];this._hass=a,b&&this.entity!==b&&(this.entity=b,this.player=new lc(a,this.config,b),this.rtl=this.computeRTL(a),this.idle=this.player.idle,this.player.trackIdle&&this.updateIdleStatus())}}get hass(){return this._hass}set overflow(a){this._overflow!==a&&(this._overflow=a)}get overflow(){return this._overflow}get name(){return this.config.name||this.player.name}setConfig(a){if(!a.entity||"media_player"!==a.entity.split(".")[0])throw new Error("Specify an entity from within the media_player domain.");const b=ta({artwork:"default",info:"default",more_info:!0,source:"default",sound_mode:"default",toggle_power:!0},a,{hide:ta({},gc,a.hide),speaker_group:ta({show_group_count:!0,platform:"sonos"},a.sonos,a.speaker_group),shortcuts:ta({label:"Shortcuts..."},a.shortcuts)});b.max_volume=+b.max_volume||100,b.min_volume=+b.min_volume||0,b.collapse=b.hide.controls||b.hide.volume,b.info=b.collapse&&"scroll"!==b.info?"short":b.info,b.flow=b.hide.icon&&b.hide.name&&b.hide.info,this.config=b}shouldUpdate(a){return void 0===this.break&&this.computeRect(this),ic.some(b=>a.has(b))&&this.player}firstUpdated(){const a=new fc(a=>{a.forEach(a=>{window.requestAnimationFrame(()=>{"scroll"===this.config.info&&this.computeOverflow(),this._resizeTimer||(this.computeRect(a),this._resizeTimer=setTimeout(()=>{this._resizeTimer=null,this.computeRect(this._resizeEntry)},250)),this._resizeEntry=a})})});a.observe(this),setTimeout(()=>this.initial=!1,250),this.edit=this.config.speaker_group.expanded||!1}updated(){"scroll"===this.config.info&&setTimeout(()=>{this.computeOverflow()},10)}render(){let a=0mb(b(),"attr__".concat(a.attr),a.prefix+a.text))):"",e.map(b=>mb(a(),"attr__".concat(b.attr),b.prefix+b.text)))}}speakerCount(){if(this.config.speaker_group.show_group_count){const a=this.player.groupCount;return 1{this.thumbnail=a}),this.picture=b),!!(c&&this.thumbnail)}computeIcon(){return this.config.icon?this.config.icon:this.player.icon||hc.DEFAULT}computeOverflow(){const a=this.shadowRoot.querySelector(".marquee");if(a){const b=a.clientWidth>a.parentNode.clientWidth;this.overflow=!!(b&&this.player.active)&&7.5+a.clientWidth/50}}computeRect(a){const b=a.contentRect||a.getBoundingClientRect(),c=b.left,d=b.width;this.break=d+2*c<390}computeRTL(a){const b=a.language||"en";return!!a.translationMetadata.translations[b]&&(a.translationMetadata.translations[b].isRTL||!1)}toggleGroupList(){this.edit=!this.edit}handleMoreInfo(a){a.stopPropagation(),this.config.more_info&&this.fire("hass-more-info",{entityId:this.config.entity})}fire(a,b,c){const d=c||{},f=null===b||void 0===b?{}:b,g=new Event(a,{bubbles:void 0===d.bubbles||d.bubbles,cancelable:!!d.cancelable,composed:void 0===d.composed||d.composed});return g.detail=f,this.dispatchEvent(g),g}updateIdleStatus(){this._idleTracker&&clearTimeout(this._idleTracker);const a=(Date.now()-new Date(this.player.updatedAt).getTime())/1e3;this._idleTracker=setTimeout(()=>{this.idle=this.player.checkIdleAfter(this.config.idle_view.after),this.player.idle=this.idle,this._idleTracker=null},1e3*(60*this.config.idle_view.after-a))}getCardSize(){return this.config.collapse?1:2}}customElements.define("mini-media-player",Bc)})})();
diff --git a/www/community/mini-media-player/mini-media-player.js.gz b/www/community/mini-media-player/mini-media-player.js.gz
new file mode 100644
index 0000000..4994012
Binary files /dev/null and b/www/community/mini-media-player/mini-media-player.js.gz differ
diff --git a/www/community/secondaryinfo-entity-row/secondaryinfo-entity-row.js b/www/community/secondaryinfo-entity-row/secondaryinfo-entity-row.js
new file mode 100644
index 0000000..e6ca89e
--- /dev/null
+++ b/www/community/secondaryinfo-entity-row/secondaryinfo-entity-row.js
@@ -0,0 +1,56 @@
+customElements.whenDefined('card-tools').then(() => {
+
+ class SecondaryInfoEntityRow extends cardTools.LitElement {
+ version() { return "0.3.1"; }
+
+ render() {
+ return cardTools.LitHtml`
+ ${this._wrappedElement}
+ `;
+ }
+
+ setConfig(config) {
+ cardTools.checkVersion(0.4);
+ this._config = config;
+ this._wrappedElement = this._createElement(config);
+ this.requestUpdate();
+ }
+
+ set hass(hass) {
+ this._hass = hass;
+ this._stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
+ this._updateElement(this._wrappedElement, hass);
+ }
+
+ _createElement(config) {
+ // Override the custom row type in order to create the 'standard' row for this entity
+ let defaultRowConfig = Object.assign(config, {type: "default"});
+ const element = cardTools.createEntityRow(defaultRowConfig);
+ return element;
+ }
+
+ async _updateElement(wrappedElement, hass) {
+ if (!wrappedElement) return;
+
+ this._wrappedElement.hass = hass;
+ await this._wrappedElement.updateComplete;
+ await this._wrappedElement.shadowRoot.querySelector("hui-generic-entity-row");
+ let secondaryInfoDiv = this._wrappedElement.shadowRoot.querySelector("hui-generic-entity-row").shadowRoot.querySelector(".secondary");
+ if (secondaryInfoDiv && this._config.secondary_info) {
+ let text = window.cardTools.parseTemplate(this._config.secondary_info, {entity: this._config.entity});
+ secondaryInfoDiv.innerHTML = text;
+ }
+ }
+ }
+ customElements.define('secondaryinfo-entity-row', SecondaryInfoEntityRow);
+
+});
+
+setTimeout(() => {
+ if (customElements.get('card-tools')) return;
+ customElements.define('secondaryinfo-entity-row', class extends HTMLElement {
+ setConfig() {
+ throw new Error("Can't find card-tools. See https://github.com/thomasloven/lovelace-card-tools");
+ }
+ });
+}, 2000);
diff --git a/www/community/secondaryinfo-entity-row/secondaryinfo-entity-row.js.gz b/www/community/secondaryinfo-entity-row/secondaryinfo-entity-row.js.gz
new file mode 100644
index 0000000..8e3ea05
Binary files /dev/null and b/www/community/secondaryinfo-entity-row/secondaryinfo-entity-row.js.gz differ
diff --git a/www/community/vertical-stack-in-card/vertical-stack-in-card.js b/www/community/vertical-stack-in-card/vertical-stack-in-card.js
new file mode 100644
index 0000000..3c133c7
--- /dev/null
+++ b/www/community/vertical-stack-in-card/vertical-stack-in-card.js
@@ -0,0 +1,176 @@
+class VerticalStackInCard extends HTMLElement {
+ constructor() {
+ super();
+ // Make use of shadowRoot to avoid conflicts when reusing
+ this.attachShadow({ mode: 'open' });
+ }
+
+ setConfig(config) {
+ if (!config || !config.cards || !Array.isArray(config.cards)) {
+ throw new Error('Card config incorrect');
+ }
+
+ this.style.boxShadow = "var(--ha-card-box-shadow, 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2))";
+ this.style.borderRadius = "var(--ha-card-border-radius, 2px)";
+ this.style.background = "var(--paper-card-background-color)";
+ this.style.display = "block";
+
+ const root = this.shadowRoot;
+ while (root.hasChildNodes()) {
+ root.removeChild(root.lastChild);
+ }
+
+ this._refCards = [];
+ if (config.title) {
+ const title = document.createElement("div");
+ title.className = "header";
+ title.style = "font-family: var(--paper-font-headline_-_font-family); -webkit-font-smoothing: var(--paper-font-headline_-_-webkit-font-smoothing); font-size: var(--paper-font-headline_-_font-size); font-weight: var(--paper-font-headline_-_font-weight); letter-spacing: var(--paper-font-headline_-_letter-spacing); line-height: var(--paper-font-headline_-_line-height);text-rendering: var(--paper-font-common-expensive-kerning_-_text-rendering);opacity: var(--dark-primary-opacity);padding: 24px 16px 0px 16px";
+ title.innerHTML = '' + config.title + '
';
+ root.appendChild(title);
+ }
+
+ const _createThing = (tag, config) => {
+ const element = document.createElement(tag);
+ try {
+ element.setConfig(config);
+ } catch (err) {
+ console.error(tag, err);
+ return _createError(err.message, config);
+ }
+ return element;
+ };
+
+ const _createError = (error, config) => {
+ return _createThing("hui-error-card", {
+ type: "error",
+ error,
+ config,
+ });
+ };
+
+ const _fireEvent = (ev, detail, entity=null) => {
+ ev = new Event(ev, {
+ bubbles: true,
+ cancelable: false,
+ composed: true,
+ });
+ ev.detail = detail || {};
+
+ if (entity) {
+ entity.dispatchEvent(ev);
+ } else {
+ document
+ .querySelector("home-assistant")
+ .shadowRoot.querySelector("home-assistant-main")
+ .shadowRoot.querySelector("app-drawer-layout partial-panel-resolver")
+ .shadowRoot.querySelector("ha-panel-lovelace")
+ .shadowRoot.querySelector("hui-root")
+ .shadowRoot.querySelector("ha-app-layout #view")
+ .firstElementChild
+ .dispatchEvent(ev);
+ }
+ }
+
+ config.cards.forEach((item) => {
+ let tag = item.type;
+
+ if (tag.startsWith("divider")) {
+ tag = `hui-divider-row`;
+ } else if (tag.startsWith("custom:")) {
+ tag = tag.substr("custom:".length);
+ } else {
+ tag = `hui-${tag}-card`;
+ }
+
+ if (customElements.get(tag)) {
+ const element = _createThing(tag, item);
+ root.appendChild(element);
+ this._refCards.push(element);
+ } else {
+ // If element doesn't exist (yet) create an error
+ const element = _createError(
+ `Custom element doesn't exist: ${tag}.`,
+ item
+ );
+ element.style.display = "None";
+
+ const time = setTimeout(() => {
+ element.style.display = "";
+ }, 2000);
+
+ // Remove error if element is defined later
+ customElements.whenDefined(tag).then(() => {
+ clearTimeout(time);
+ _fireEvent("ll-rebuild", {}, element);
+ });
+
+ root.appendChild(element);
+ this._refCards.push(element);
+ }
+ });
+ }
+
+ set hass(hass) {
+ if (this._refCards) {
+ this._refCards.forEach((card) => {
+ card.hass = hass;
+ });
+ }
+ }
+
+ connectedCallback() {
+ this._refCards.forEach((element) => {
+ let fn = () => {
+ this._card(element);
+ };
+
+ if(element.updateComplete) {
+ element.updateComplete.then(fn);
+ } else {
+ fn();
+ }
+ });
+ }
+
+ _card(element) {
+ if (element.shadowRoot) {
+ if (!element.shadowRoot.querySelector('ha-card')) {
+ let searchEles = element.shadowRoot.getElementById("root");
+ if (!searchEles) {
+ searchEles = element.shadowRoot.getElementById("card");
+ }
+ if (!searchEles) return;
+ searchEles = searchEles.childNodes;
+ for (let i = 0; i < searchEles.length; i++) {
+ if(searchEles[i].style !== undefined){
+ searchEles[i].style.margin = "0px";
+ }
+ this._card(searchEles[i]);
+ }
+ } else {
+ element.shadowRoot.querySelector('ha-card').style.boxShadow = 'none';
+ }
+ } else {
+ if (typeof element.querySelector === 'function' && element.querySelector('ha-card')) {
+ element.querySelector('ha-card').style.boxShadow = 'none';
+ }
+ let searchEles = element.childNodes;
+ for (let i = 0; i < searchEles.length; i++) {
+ if (searchEles[i] && searchEles[i].style) {
+ searchEles[i].style.margin = "0px";
+ }
+ this._card(searchEles[i]);
+ }
+ }
+ }
+
+ getCardSize() {
+ let totalSize = 0;
+ this._refCards.forEach((element) => {
+ totalSize += typeof element.getCardSize === 'function' ? element.getCardSize() : 1;
+ });
+ return totalSize;
+ }
+}
+
+customElements.define('vertical-stack-in-card', VerticalStackInCard);
diff --git a/www/community/vertical-stack-in-card/vertical-stack-in-card.js.gz b/www/community/vertical-stack-in-card/vertical-stack-in-card.js.gz
new file mode 100644
index 0000000..1466f1b
Binary files /dev/null and b/www/community/vertical-stack-in-card/vertical-stack-in-card.js.gz differ
diff --git a/www/lovelace/home/xiaomi_vacuum_02.jpg b/www/lovelace/home/xiaomi_vacuum_02.jpg
new file mode 100644
index 0000000..52753ac
Binary files /dev/null and b/www/lovelace/home/xiaomi_vacuum_02.jpg differ
diff --git a/www/plugins/lovelace-auto-entities b/www/plugins/lovelace-auto-entities
deleted file mode 160000
index be13234..0000000
--- a/www/plugins/lovelace-auto-entities
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit be13234a43fa35b2e345fdd73482c8cd2d709e4e
diff --git a/www/plugins/lovelace-card-modder b/www/plugins/lovelace-card-modder
deleted file mode 160000
index f3d96f7..0000000
--- a/www/plugins/lovelace-card-modder
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f3d96f73f158517acac4d836970e623e498cfccd
diff --git a/www/plugins/lovelace-card-tools b/www/plugins/lovelace-card-tools
deleted file mode 160000
index deb8e38..0000000
--- a/www/plugins/lovelace-card-tools
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit deb8e38741b7472cd92c50f69fb417e49ad2cb1d
diff --git a/www/plugins/lovelace-fold-entity-row b/www/plugins/lovelace-fold-entity-row
deleted file mode 160000
index 6d11d3c..0000000
--- a/www/plugins/lovelace-fold-entity-row
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 6d11d3cc65eb9d35c5f64d5c0139cbf5f7ae31c5
diff --git a/www/plugins/lovelace-layout-card b/www/plugins/lovelace-layout-card
deleted file mode 160000
index e0ec2f2..0000000
--- a/www/plugins/lovelace-layout-card
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e0ec2f21ad0a0b04c74292707f8a1f3e6c813b30