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)]] +
+ + +
+
+ + + + +
`; + } + + 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` + + + +
+
+
[[_config.labels.status]]: [[stateObj.attributes.status]]
+
[[_config.labels.battery]]: [[stateObj.attributes.battery_level]] %
+
[[_config.labels.mode]]: [[stateObj.attributes.fan_speed]]
+
+ +
+ +
+ `; + } + + 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
\n
\n ","\n
\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
\n ","\n \n \n \n \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 \n \n \n \n \n \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 \n \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 ","\n \n \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
\n \n
\n \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