From 8a0331ed7542718b3f5305183831e8ff9c717da8 Mon Sep 17 00:00:00 2001 From: Florian Krebs Date: Thu, 21 May 2026 11:12:07 +0200 Subject: [PATCH] missing files --- .HA_VERSION | 2 +- .storage/core.area_registry | 13 + .storage/energy | 39 +- .storage/lovelace.dashboard_grow | 765 +++++++++++++++++------- .storage/lovelace.dashboard_haustechnik | 569 ++++++++++++++++-- .storage/lovelace.dashboard_spa | 425 +++++-------- .storage/lovelace.lovelace | 466 +++++++++++---- .storage/lovelace_resources | 18 +- .storage/schedule | 50 +- .storage/scheduler.storage | 48 +- automations.yaml | 7 +- configuration.yaml | 40 +- 12 files changed, 1658 insertions(+), 784 deletions(-) diff --git a/.HA_VERSION b/.HA_VERSION index 881a774..ee73ae9 100644 --- a/.HA_VERSION +++ b/.HA_VERSION @@ -1 +1 @@ -2026.4.4 \ No newline at end of file +2026.5.3 \ No newline at end of file diff --git a/.storage/core.area_registry b/.storage/core.area_registry index 023602e..7b43f71 100644 --- a/.storage/core.area_registry +++ b/.storage/core.area_registry @@ -250,6 +250,19 @@ "temperature_entity_id": null, "created_at": "2026-04-13T06:45:41.915906+00:00", "modified_at": "2026-04-13T06:45:41.915909+00:00" + }, + { + "aliases": [], + "floor_id": "erdgeschoss", + "humidity_entity_id": null, + "icon": "mdi:server", + "id": "it_cabinet", + "labels": [], + "name": "IT Cabinet", + "picture": null, + "temperature_entity_id": null, + "created_at": "2026-05-20T15:16:52.111409+00:00", + "modified_at": "2026-05-20T15:16:52.111413+00:00" } ] } diff --git a/.storage/energy b/.storage/energy index 1513f21..9fc7b34 100644 --- a/.storage/energy +++ b/.storage/energy @@ -4,26 +4,13 @@ "key": "energy", "data": { "energy_sources": [ - { - "type": "grid", - "cost_adjustment_day": 0.0, - "stat_energy_from": "sensor.tibber_pulse_zuhause_zahlerstand_verbrauch", - "stat_cost": null, - "entity_energy_price": "sensor.zuhause_strompreis", - "number_energy_price": null, - "stat_energy_to": "sensor.tibber_pulse_zuhause_zahlerstand_einspeisung", - "stat_compensation": null, - "entity_energy_price_export": null, - "number_energy_price_export": 0.0695, - "stat_rate": "sensor.tibber_pulse_zuhause_leistung" - }, { "type": "solar", "stat_energy_from": "sensor.powerocean_hj37zdh5zg5w0109_solarertrag_heute", "config_entry_solar_forecast": [ "01J8CDN8M8JEDRF4BA6ENG0KQ7" ], - "stat_rate": "sensor.powerocean_mpptpv_pwrtotal" + "stat_rate": "sensor.tibber_pulse_zuhause_einspeiseleistung" }, { "type": "battery", @@ -42,6 +29,22 @@ "stat_rate": "sensor.battery_hj3azdh5zg3g0490_batterieleistung" }, "stat_rate": "sensor.battery_hj3azdh5zg3g0490_batterieleistung" + }, + { + "type": "grid", + "stat_energy_from": "sensor.electricity_klostergasse_20a_gesamtbezug", + "stat_energy_to": "sensor.electricity_klostergasse_20a_gesamteinspeisung", + "stat_cost": null, + "stat_compensation": null, + "entity_energy_price": "sensor.zuhause_strompreis", + "number_energy_price": null, + "entity_energy_price_export": null, + "number_energy_price_export": 0.00803, + "cost_adjustment_day": 0.0, + "power_config": { + "stat_rate": "sensor.tibber_pulse_zuhause_leistung" + }, + "stat_rate": "sensor.tibber_pulse_zuhause_leistung" } ], "device_consumption": [ @@ -74,10 +77,6 @@ "stat_consumption": "sensor.kuche_geschirrspuler_energy", "name": "Geschirrspüler" }, - { - "stat_consumption": "sensor.kuche_kuhlschrank_energy", - "name": "Kühlschrank" - }, { "stat_consumption": "sensor.technikraum_netzwerkschrank_energy", "name": "Netzwerkschrank" @@ -87,6 +86,10 @@ "stat_rate": "sensor.whirlpool_leistung", "name": "Whirlpool" }, + { + "stat_consumption": "sensor.kuche_kuhlschrank_energy", + "name": "Kühlschrank" + }, { "stat_consumption": "sensor.all_standby_energy", "stat_rate": "sensor.all_standby_power", diff --git a/.storage/lovelace.dashboard_grow b/.storage/lovelace.dashboard_grow index 7100861..897f6ee 100644 --- a/.storage/lovelace.dashboard_grow +++ b/.storage/lovelace.dashboard_grow @@ -12,19 +12,33 @@ "badges": [ { "type": "entity", - "entity": "sensor.spider_farmer_80f1b2b3b64a_temperature" + "entity": "sensor.spider_farmer_80f1b2b3b64a_temperature", + "color": "#ff6b35" }, { "type": "entity", - "entity": "sensor.spider_farmer_80f1b2b3b64a_humidity" + "entity": "sensor.spider_farmer_80f1b2b3b64a_humidity", + "color": "#00bfff" }, { "type": "entity", - "entity": "sensor.spider_farmer_80f1b2b3b64a_vpd" + "entity": "sensor.spider_farmer_80f1b2b3b64a_vpd", + "color": "#ff9800" }, { "type": "entity", - "entity": "sensor.grow_tent_power" + "entity": "sensor.spider_farmer_80f1b2b3b64a_co2", + "color": "#a855f7" + }, + { + "type": "entity", + "entity": "sensor.spider_farmer_80f1b2b3b64a_ppfd", + "color": "#fbbf24" + }, + { + "type": "entity", + "entity": "sensor.grow_tent_power", + "color": "#facc15" } ], "sections": [ @@ -33,7 +47,12 @@ "cards": [ { "type": "heading", - "heading": "Surveillance & Environment" + "heading": "🌿 Monitoring & Klima" + }, + { + "type": "heading", + "heading": "🎥 Kamera & Überwachung", + "heading_style": "title" }, { "type": "custom:advanced-camera-card", @@ -53,13 +72,23 @@ }, "timeline": { "enabled": false + }, + "iris": { + "enabled": true } } + }, + "live": { + "zoomable": false, + "draggable": false, + "transition_effect": "none", + "display": {} } }, { "type": "heading", - "heading": "Plant Health" + "heading": "🌱 Pflanzenstatus", + "heading_style": "title" }, { "type": "horizontal-stack", @@ -71,7 +100,7 @@ "type": "custom:mushroom-template-card", "primary": "P1", "secondary": "{{ '⚠️' if is_state('plant.grow_plant_1', 'problem') else '✅' }}", - "icon": "mdi:flower", + "icon": "mdi:cannabis", "icon_color": "{{ 'red' if is_state('plant.grow_plant_1', 'problem') else 'green' }}", "layout": "vertical" }, @@ -100,7 +129,7 @@ "type": "custom:mushroom-template-card", "primary": "P2", "secondary": "{{ '⚠️' if is_state('plant.grow_plant_2', 'problem') else '✅' }}", - "icon": "mdi:flower", + "icon": "mdi:cannabis", "icon_color": "{{ 'red' if is_state('plant.grow_plant_2', 'problem') else 'green' }}", "layout": "vertical" }, @@ -129,7 +158,7 @@ "type": "custom:mushroom-template-card", "primary": "P3", "secondary": "{{ '⚠️' if is_state('plant.grow_plant_3', 'problem') else '✅' }}", - "icon": "mdi:flower", + "icon": "mdi:cannabis", "icon_color": "{{ 'red' if is_state('plant.grow_plant_3', 'problem') else 'green' }}", "layout": "vertical" }, @@ -158,7 +187,7 @@ "type": "custom:mushroom-template-card", "primary": "P4", "secondary": "{{ '⚠️' if is_state('plant.grow_plant_4', 'problem') else '✅' }}", - "icon": "mdi:flower", + "icon": "mdi:cannabis", "icon_color": "{{ 'red' if is_state('plant.grow_plant_4', 'problem') else 'green' }}", "layout": "vertical" }, @@ -187,7 +216,7 @@ "type": "custom:mushroom-template-card", "primary": "P5", "secondary": "{{ '⚠️' if is_state('plant.grow_plant_5', 'problem') else '✅' }}", - "icon": "mdi:flower", + "icon": "mdi:cannabis", "icon_color": "{{ 'red' if is_state('plant.grow_plant_5', 'problem') else 'green' }}", "layout": "vertical" }, @@ -210,214 +239,414 @@ ] } ] - } - ] - }, - { - "type": "grid", - "cards": [ + }, { "type": "heading", - "heading": "Secondary Environment" + "heading": "📊 Sensorübersicht", + "heading_style": "title" }, { - "type": "vertical-stack", - "cards": [ - { - "type": "custom:apexcharts-card", - "graph_span": "48h", - "header": { - "show": true, - "title": "48h Klima-Vergleich (Geglättet)" - }, - "yaxis": [ - { - "id": "temp", - "min": 10, - "max": 35, - "apex_config": { - "tickAmount": 5 - } - }, - { - "id": "hum", - "opposite": true, - "min": 20, - "max": 100, - "apex_config": { - "tickAmount": 5 - } - } - ], - "series": [ - { - "entity": "sensor.spider_farmer_80f1b2b3b64a_temperature", - "name": "Zelt Temp", - "yaxis_id": "temp", - "stroke_width": 3, - "color": "#00ff00", - "group_by": { - "func": "avg", - "duration": "10m" - } - }, - { - "entity": "sensor.0x00158d0002c9fa8b_temperature", - "name": "Außen Temp (ZB)", - "yaxis_id": "temp", - "stroke_width": 2, - "color": "darkgreen", - "group_by": { - "func": "avg", - "duration": "10m" - } - }, - { - "entity": "sensor.spider_farmer_80f1b2b3b64a_humidity", - "name": "Zelt Hum", - "yaxis_id": "hum", - "stroke_width": 3, - "color": "#00bfff", - "group_by": { - "func": "avg", - "duration": "10m" - } - }, - { - "entity": "sensor.0x00158d0002c9fa8b_humidity", - "name": "Außen Hum (ZB)", - "yaxis_id": "hum", - "stroke_width": 2, - "color": "#1a4b6e", - "group_by": { - "func": "avg", - "duration": "10m" - } - } - ], - "apex_config": { - "stroke": { - "curve": "smooth", - "dashArray": [ - 0, - 5, - 0, - 5 - ] - }, - "legend": { - "show": true - }, - "grid": { - "borderColor": "#333", - "strokeDashArray": 4 - } - } - }, - { - "type": "custom:apexcharts-card", - "graph_span": "48h", - "header": { - "show": true, - "title": "48h VPD Verlauf (kPa)" - }, - "yaxis": [ - { - "id": "vpd", - "min": 0, - "max": 2.5, - "decimals": 2, - "apex_config": { - "tickAmount": 5 - } - } - ], - "series": [ - { - "entity": "sensor.spider_farmer_80f1b2b3b64a_vpd", - "name": "Zelt VPD", - "yaxis_id": "vpd", - "stroke_width": 3, - "color": "#ff9800", - "group_by": { - "func": "avg", - "duration": "10m" - } - } - ], - "apex_config": { - "stroke": { - "curve": "smooth" - }, - "annotations": { - "yaxis": [ - { - "y": 0.8, - "y2": 1.2, - "borderColor": "#00ff00", - "fillColor": "#00ff00", - "opacity": 0.1, - "label": { - "text": "Optimum Veg", - "style": { - "background": "#00ff00", - "color": "#000" - } - } - } - ] - }, - "legend": { - "show": true - }, - "grid": { - "borderColor": "#333", - "strokeDashArray": 4 - } - } - } - ] - }, - { - "type": "grid", - "columns": 2, "square": false, + "type": "grid", "cards": [ + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_temperature", + "name": "°C Zelt", + "icon": "mdi:thermometer", + "icon_color": "#ff6b35" + }, { "type": "custom:mushroom-entity-card", "entity": "sensor.grow_env_sensor_1_temperature", - "name": "S1 Innen", - "icon_color": "orange" + "name": "°C Boden", + "icon": "mdi:thermometer-lines", + "icon_color": "#ff8c42" }, { "type": "custom:mushroom-entity-card", "entity": "sensor.0x00158d0002c9fa8b_temperature", - "name": "ZB Außen", - "icon_color": "blue" + "name": "°C Garage", + "icon": "mdi:thermometer-low", + "icon_color": "#4a9eff" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_humidity", + "name": "rH Zelt", + "icon": "mdi:water-percent", + "icon_color": "#00bfff" }, { "type": "custom:mushroom-entity-card", "entity": "sensor.grow_env_sensor_1_humidity", - "name": "S1 Feuchte", - "icon_color": "cyan" + "name": "rH Boden", + "icon": "mdi:water-percent", + "icon_color": "#29d8ff" }, { "type": "custom:mushroom-entity-card", "entity": "sensor.0x00158d0002c9fa8b_humidity", - "name": "ZB Feuchte", - "icon_color": "light-blue" + "name": "rH Garage", + "icon": "mdi:water-percent", + "icon_color": "#1a4b6e" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_vpd", + "name": "VPD", + "icon": "mdi:cloud-percent", + "icon_color": "#ff9800" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_co2", + "name": "CO₂", + "icon": "mdi:molecule-co2", + "icon_color": "#a855f7" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_ppfd", + "name": "PPFD", + "icon": "mdi:white-balance-sunny", + "icon_color": "#fbbf24" }, { "type": "custom:mushroom-entity-card", "entity": "sensor.grow_env_sensor_1_pressure", - "name": "Druck In" + "name": "hPa Boden", + "icon": "mdi:gauge", + "icon_color": "#94a3b8" }, { "type": "custom:mushroom-entity-card", "entity": "sensor.0x00158d0002c9fa8b_pressure", - "name": "Druck Out" + "name": "hPa Garage", + "icon": "mdi:gauge-low", + "icon_color": "#64748b" } - ] + ], + "columns": 3 + }, + { + "type": "heading", + "heading": "📈 Klimaverlauf (48h)", + "heading_style": "title" + }, + { + "type": "custom:apexcharts-card", + "graph_span": "48h", + "header": { + "show": true, + "title": "🌡️ Temperatur & Luftfeuchte" + }, + "yaxis": [ + { + "id": "temp", + "min": 10, + "max": 35, + "apex_config": { + "tickAmount": 5 + } + }, + { + "id": "hum", + "opposite": true, + "min": 20, + "max": 100, + "apex_config": { + "tickAmount": 5 + } + } + ], + "series": [ + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_temperature", + "name": "Zelt Temp", + "yaxis_id": "temp", + "stroke_width": 3, + "color": "#ff6b35", + "group_by": { + "func": "avg", + "duration": "10m" + } + }, + { + "entity": "sensor.0x00158d0002c9fa8b_temperature", + "name": "Garage Temp", + "yaxis_id": "temp", + "stroke_width": 2, + "color": "#ff8c42", + "group_by": { + "func": "avg", + "duration": "10m" + } + }, + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_humidity", + "name": "Zelt Hum", + "yaxis_id": "hum", + "stroke_width": 3, + "color": "#00bfff", + "group_by": { + "func": "avg", + "duration": "10m" + } + }, + { + "entity": "sensor.0x00158d0002c9fa8b_humidity", + "name": "Garage Hum", + "yaxis_id": "hum", + "stroke_width": 2, + "color": "#1a4b6e", + "group_by": { + "func": "avg", + "duration": "10m" + } + } + ], + "apex_config": { + "stroke": { + "curve": "smooth", + "dashArray": [ + 0, + 5, + 0, + 5 + ] + }, + "legend": { + "show": true + }, + "grid": { + "borderColor": "#333", + "strokeDashArray": 4 + } + } + }, + { + "type": "custom:apexcharts-card", + "graph_span": "48h", + "header": { + "show": true, + "title": "🟡 PPFD" + }, + "yaxis": [ + { + "id": "µmol/m²/s", + "min": 200, + "max": 1000, + "apex_config": { + "tickAmount": 5 + } + } + ], + "series": [ + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_ppfd", + "name": "PPFD", + "yaxis_id": "µmol/m²/s", + "stroke_width": 3, + "color": "#fbbf24", + "group_by": { + "func": "avg", + "duration": "10m" + } + } + ], + "apex_config": { + "stroke": { + "curve": "smooth" + }, + "annotations": { + "yaxis": [ + { + "y": 400, + "borderColor": "#22c55e", + "fillColor": "#22c55e", + "opacity": 0.15, + "label": { + "text": "Keimling", + "style": { + "background": "#22c55e", + "color": "#000" + } + } + }, + { + "y": 600, + "borderColor": "#fbbf24", + "fillColor": "#fbbf24", + "opacity": 0.1, + "label": { + "text": "Wachstum", + "style": { + "background": "#fbbf24", + "color": "#000" + } + } + }, + { + "y": 1000, + "borderColor": "#fbbf24", + "fillColor": "#fbbf24", + "opacity": 0.1, + "label": { + "text": "Blüte", + "style": { + "background": "#fbbf24", + "color": "#000" + } + } + } + ] + }, + "legend": { + "show": true + }, + "grid": { + "borderColor": "#333", + "strokeDashArray": 4 + } + } + }, + { + "type": "custom:apexcharts-card", + "graph_span": "48h", + "header": { + "show": true, + "title": "⚪ VPD (kPa)" + }, + "yaxis": [ + { + "id": "vpd", + "min": 0, + "max": 2.5, + "decimals": 2, + "apex_config": { + "tickAmount": 5 + } + } + ], + "series": [ + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_vpd", + "name": "VPD", + "yaxis_id": "vpd", + "stroke_width": 3, + "color": "#ff9800", + "group_by": { + "func": "avg", + "duration": "10m" + } + } + ], + "apex_config": { + "stroke": { + "curve": "smooth" + }, + "annotations": { + "yaxis": [ + { + "y": 0.8, + "y2": 1.2, + "borderColor": "#22c55e", + "fillColor": "#22c55e", + "opacity": 0.15, + "label": { + "text": "Optimum Veg", + "style": { + "background": "#22c55e", + "color": "#000" + } + } + }, + { + "y": 1.2, + "y2": 1.6, + "borderColor": "#fbbf24", + "fillColor": "#fbbf24", + "opacity": 0.1, + "label": { + "text": "Optimum Blüte", + "style": { + "background": "#fbbf24", + "color": "#000" + } + } + } + ] + }, + "legend": { + "show": true + }, + "grid": { + "borderColor": "#333", + "strokeDashArray": 4 + } + } + }, + { + "type": "custom:apexcharts-card", + "graph_span": "48h", + "header": { + "show": true, + "title": "🟣 CO₂ (ppm)" + }, + "yaxis": [ + { + "id": "co2", + "min": 300, + "max": 2000, + "apex_config": { + "tickAmount": 5 + } + } + ], + "series": [ + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_co2", + "name": "CO₂", + "yaxis_id": "co2", + "stroke_width": 3, + "color": "#a855f7", + "group_by": { + "func": "avg", + "duration": "10m" + } + } + ], + "apex_config": { + "stroke": { + "curve": "smooth" + }, + "annotations": { + "yaxis": [ + { + "y": 800, + "y2": 1200, + "borderColor": "#a855f7", + "fillColor": "#a855f7", + "opacity": 0.12, + "label": { + "text": "Optimum", + "style": { + "background": "#a855f7", + "color": "#fff" + } + } + } + ] + }, + "legend": { + "show": true + }, + "grid": { + "borderColor": "#333", + "strokeDashArray": 4 + } + } } ] }, @@ -426,23 +655,89 @@ "cards": [ { "type": "heading", - "heading": "Equipment & Controls" + "heading": "⚙️ Steuerung & Planung" + }, + { + "type": "heading", + "heading": "📅 Grow Planer", + "heading_style": "title" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "input_datetime.grow_startdatum", + "name": "Startdatum", + "icon": "mdi:calendar-start", + "icon_color": "#22c55e" + }, + { + "type": "custom:stack-in-card", + "cards": [ + { + "type": "markdown", + "content": "{% set start_state = states('input_datetime.grow_startdatum') %} {% if start_state not in ['unknown', 'unavailable'] %}\n {% set start = as_timestamp(start_state) %}\n {% set heute = as_timestamp(now().strftime('%Y-%m-%d')) %}\n {% set tage = ((heute - start) / 86400) | int %}\n {% set start_dt = start_state | as_datetime %}\n ### 🌱 Aktueller Tag: {{ tage }}\n | Phase | Zeitraum | Status |\n | :--- | :--- | :--- |\n | 🥚 **Keimung** | bis {{ (start_dt + timedelta(days=5)).strftime('%d.%m.') }} | {{ '🟢 Aktiv' if tage <= 5 else '✅ OK' }} |\n | 🌿 **Sämling** | bis {{ (start_dt + timedelta(days=19)).strftime('%d.%m.') }} | {{ '⏳' if tage < 6 else ('🟢 Aktiv' if tage <= 19 else '✅ OK') }} |\n | 💪 **Wachstum** | {{ (start_dt + timedelta(days=20)).strftime('%d.%m.') }} – {{ (start_dt + timedelta(days=35)).strftime('%d.%m.') }} | {{ '⏳' if tage < 20 else ('🟢 Aktiv' if tage <= 35 else '✅ OK') }} |\n | 🌸 **Blüte** | {{ (start_dt + timedelta(days=36)).strftime('%d.%m.') }} – {{ (start_dt + timedelta(days=90)).strftime('%d.%m.') }} | {{ '⏳' if tage < 36 else ('🟢 Aktiv' if tage <= 90 else '✅ OK') }} |\n\n 🍀 **Ernte ca.: {{ (start_dt + timedelta(days=80)).strftime('%d.%m.%Y') }}**\n ---\n 🌿 **Sorten:** 2× Amnesia XXL · 2× Sticky Orange · 1× Purple Skunk\n{% endif %}\n" + } + ] + }, + { + "type": "heading", + "heading": "🚀 Grow Plan Status", + "heading_style": "title" }, { "type": "tile", "entity": "binary_sensor.spider_farmer_80f1b2b3b64a_growth_plan_running", - "name": "Growth plan active", + "name": "Growth Plan aktiv", + "color": "#22c55e", "vertical": false, "features_position": "bottom" }, { "type": "tile", "entity": "sensor.spider_farmer_80f1b2b3b64a_growth_progress", - "name": "Growth plan progress", - "icon": "fa6-solid:percent", + "name": "Fortschritt", + "icon": "mdi:progress-clock", + "color": "#22c55e", "vertical": false, "features_position": "bottom" }, + { + "type": "glance", + "title": "Plan Details", + "show_name": true, + "show_icon": true, + "entities": [ + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_growth_plan_day", + "name": "Tag", + "icon": "mdi:counter" + }, + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_growth_plan_total_days", + "name": "Gesamt", + "icon": "mdi:calendar-range" + }, + { + "entity": "sensor.spider_farmer_80f1b2b3b64a_growth_plan_remaining", + "name": "Verbleibend", + "icon": "mdi:calendar-clock" + }, + { + "entity": "binary_sensor.spider_farmer_80f1b2b3b64a_day_mode", + "name": "Tagmodus", + "icon": "mdi:weather-sunny" + }, + { + "entity": "binary_sensor.spider_farmer_80f1b2b3b64a_day_environment_active", + "name": "Tag-Env", + "icon": "mdi:leaf" + } + ] + }, + { + "type": "heading", + "heading": "💡 Equipment & Steuerung", + "heading_style": "title" + }, { "type": "horizontal-stack", "cards": [ @@ -453,6 +748,13 @@ "show_brightness_control": true, "use_light_color": true }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_ppfd", + "name": "PPFD", + "icon": "mdi:white-balance-sunny", + "icon_color": "#fbbf24" + }, { "type": "custom:mushroom-fan-card", "entity": "fan.spider_farmer_80f1b2b3b64a_blower", @@ -476,52 +778,87 @@ "type": "custom:mushroom-entity-card", "entity": "fan.spider_farmer_80f1b2b3b64a_heater", "name": "Heater", - "icon": "mdi:fire" + "icon": "mdi:fire", + "icon_color": "#ff6b35" } ] }, + { + "type": "heading", + "heading": "⚡ Stromverbrauch", + "heading_style": "title" + }, { "type": "glance", + "show_name": true, + "show_icon": true, "entities": [ { "entity": "sensor.grow_tent_power", - "name": "Watt" + "name": "Watt", + "icon": "mdi:flash" }, { "entity": "sensor.grow_tent_current", - "name": "Ampere" + "name": "Ampere", + "icon": "mdi:current-ac" }, { "entity": "sensor.grow_tent_voltage", - "name": "Volt" + "name": "Volt", + "icon": "mdi:sine-wave" }, { "entity": "binary_sensor.grow_tent_consumer_connected", - "name": "Status" + "name": "Status", + "icon": "mdi:power-plug" } ] - } - ] - }, - { - "type": "grid", - "cards": [ + }, { "type": "heading", - "heading": "Grow Planer" + "heading": "🔧 Gerätediagnose", + "heading_style": "title" }, { - "type": "custom:mushroom-entity-card", - "entity": "input_datetime.grow_startdatum", - "name": "Startdatum", - "icon": "mdi:calendar-start" - }, - { - "type": "custom:stack-in-card", + "type": "grid", + "columns": 3, + "square": false, "cards": [ { - "type": "markdown", - "content": "{% set start_state = states('input_datetime.grow_startdatum') %} {% if start_state not in ['unknown', 'unavailable'] %}\n {% set start = as_timestamp(start_state) %}\n {% set heute = as_timestamp(now().strftime('%Y-%m-%d')) %}\n {% set tage = ((heute - start) / 86400) | int %}\n {% set start_dt = start_state | as_datetime %}\n ### Aktueller Tag: {{ tage }}\n | Phase | Zeitraum | Status |\n | :--- | :--- | :--- |\n | **Keimung** | bis {{ (start_dt + timedelta(days=5)).strftime('%d.%m.') }} | {{ '🟢 Aktiv' if tage <= 5 else '✅ OK' }} |\n | **Sämling** | bis {{ (start_dt + timedelta(days=19)).strftime('%d.%m.') }} | {{ '⏳' if tage < 6 else ('🟢 Aktiv' if tage <= 19 else '✅ OK') }} |\n | **Wachstum** | {{ (start_dt + timedelta(days=20)).strftime('%d.%m.') }} bis {{ (start_dt + timedelta(days=35)).strftime('%d.%m.') }} | {{ '⏳' if tage < 20 else ('🟢 Aktiv' if tage <= 35 else '✅ OK') }} |\n | **Blüte** | {{ (start_dt + timedelta(days=36)).strftime('%d.%m.') }} bis {{ (start_dt + timedelta(days=90)).strftime('%d.%m.') }} | {{ '⏳' if tage < 36 else ('🟢 Aktiv' if tage <= 90 else '✅ OK') }} |\n \n **Voraussichtliche Ernte: {{ (start_dt + timedelta(days=80)).strftime('%d.%m.%y') }}**\n ---\n **Sorten:** 2x Amnesia XXL, 2x Sticky Orange, 1x Purple Skunk\n{% endif %}\n" + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_wifi_rssi", + "name": "WiFi Signal", + "icon": "mdi:wifi", + "icon_color": "#60a5fa" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "binary_sensor.spider_farmer_80f1b2b3b64a_wifi_connected", + "name": "WiFi Status", + "icon": "mdi:wifi-check", + "icon_color": "#22c55e" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_uptime", + "name": "Uptime", + "icon": "mdi:timer-outline", + "icon_color": "#94a3b8" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_free_memory", + "name": "RAM frei", + "icon": "mdi:memory", + "icon_color": "#94a3b8" + }, + { + "type": "custom:mushroom-entity-card", + "entity": "sensor.spider_farmer_80f1b2b3b64a_firmware_version", + "name": "Firmware", + "icon": "mdi:chip", + "icon_color": "#94a3b8" } ] } diff --git a/.storage/lovelace.dashboard_haustechnik b/.storage/lovelace.dashboard_haustechnik index f69a6af..9248fd1 100644 --- a/.storage/lovelace.dashboard_haustechnik +++ b/.storage/lovelace.dashboard_haustechnik @@ -100,12 +100,12 @@ "graph_span": "24h", "series": [ { - "entity": "sensor.powerocean_hj37zdh5zg5w0109_solarertrag_mppt", + "entity": "sensor.powerocean_hj37zdh5zg5w0109_solar_gesamtleistung", "name": "Solar", "color": "#f9a825" }, { - "entity": "sensor.powerocean_hj37zdh5zg5w0109_netzleistung_system", + "entity": "sensor.powerocean_hj37zdh5zg5w0109_hausverbrauch_berechnet", "name": "Eigenverbrauch", "color": "#e53935" }, @@ -186,77 +186,269 @@ }, { "type": "custom:apexcharts-card", + "update_interval": "5m", + "graph_span": "48h", + "span": { + "start": "day" + }, + "experimental": { + "hidden_by_default": true + }, "header": { "show": true, - "title": "Strompreis", - "show_states": false, - "standard_format": true, - "disable_actions": true + "title": "Preisniveau", + "show_states": false + }, + "now": { + "show": true, + "color": "#ffffff" + }, + "all_series_config": { + "float_precision": 2 }, "apex_config": { + "chart": { + "animations": { + "enabled": false + }, + "toolbar": { + "show": false + }, + "zoom": { + "enabled": false + } + }, + "stroke": { + "curve": "stepline", + "dashArray": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4 + ] + }, + "fill": { + "type": "gradient", + "opacity": 0.45, + "gradient": { + "shade": "light", + "type": "vertical", + "shadeIntensity": 0.2, + "opacityFrom": [ + 0.5, + 0.7, + 0.7, + 0.7, + 0.7, + 0.7, + 0.7, + 0 + ], + "opacityTo": 0.25, + "stops": [ + 50, + 100 + ] + } + }, + "dataLabels": { + "enabled": false + }, "legend": { - "show": false + "show": true, + "position": "bottom", + "horizontalAlign": "center", + "markers": { + "size": 0 + }, + "itemMargin": { + "horizontal": 15 + } + }, + "grid": { + "show": true, + "borderColor": "rgba(144, 164, 174, 0.35)", + "strokeDashArray": 0, + "xaxis": { + "lines": { + "show": false + } + }, + "yaxis": { + "lines": { + "show": true + } + } + }, + "markers": { + "size": 0, + "hover": { + "size": 3 + }, + "showNullDataPoints": false + }, + "tooltip": { + "enabled": true, + "shared": true, + "enabledOnSeries": [ + 2, + 3, + 4, + 5, + 6 + ], + "marker": { + "show": false + }, + "x": { + "show": false + } } }, "yaxis": [ { "id": "price", - "min": "~0.1", - "max": "~0.4", - "align_to": 1, - "decimals": 2 + "min": 0, + "max": 40, + "apex_config": { + "title": { + "text": "ct/kWh" + }, + "decimalsInFloat": 0, + "forceNiceScale": true, + "showAlways": true, + "tickAmount": 4 + } + }, + { + "id": "highlight", + "min": 0, + "max": 1, + "show": false, + "opposite": true, + "apex_config": { + "forceNiceScale": true, + "tickAmount": 4 + } } ], - "chart_type": "line", - "graph_span": "1.5d", - "span": { - "start": "day" - }, - "now": { - "show": true, - "label": "Jetzt" - }, - "experimental": { - "color_threshold": true - }, "series": [ { - "entity": "sensor.epex_spot_data_total_price", - "yaxis_id": "price", - "stroke_width": 2, + "entity": "sun.sun", + "name": "▼ Bestpreis-Zeitraum", + "type": "area", + "color": "rgba(46, 204, 113, 0.05)", + "yaxis_id": "highlight", + "stroke_width": 0, "show": { - "legend_value": false + "legend_value": false, + "in_header": false, + "in_legend": true }, + "data_generator": "const ed=new Date(); ed.setDate(ed.getDate()+3); ed.setHours(0,0,0,0); const es=ed.getFullYear()+'-'+String(ed.getMonth()+1).padStart(2,'0')+'-'+String(ed.getDate()).padStart(2,'0')+' 00:00:00'; const r=await hass.callWS({type:'call_service',domain:'tibber',service:'get_prices',return_response:true,service_data:{end:es}}); const a=r.response.prices.Zuhause.map(p=>({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tC=m-0.5*sd; return a.map(p=>[p.ts,p.ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tE=m+0.5*sd; return a.map(p=>[p.ts,p.ct>=tE?1:null]);" + }, + { + "entity": "sun.sun", + "name": "Sehr günstig", + "type": "area", + "color": "#2ecc71", + "yaxis_id": "price", + "stroke_width": 1.5, + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const ed=new Date(); ed.setDate(ed.getDate()+3); ed.setHours(0,0,0,0); const es=ed.getFullYear()+'-'+String(ed.getMonth()+1).padStart(2,'0')+'-'+String(ed.getDate()).padStart(2,'0')+' 00:00:00'; const r=await hass.callWS({type:'call_service',domain:'tibber',service:'get_prices',return_response:true,service_data:{end:es}}); const a=r.response.prices.Zuhause.map(p=>({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tVC=m-1.5*sd; return a.map((p,i)=>{\n const here=p.ct0&&a[i-1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tVC=m-1.5*sd; const tC=m-0.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tVC&&p.ct0&&a[i-1].ct>=tVC&&a[i-1].ct=tVC&&a[i+1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tC=m-0.5*sd; const tE=m+0.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tC&&p.ct0&&a[i-1].ct>=tC&&a[i-1].ct=tC&&a[i+1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tE=m+0.5*sd; const tVE=m+1.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tE&&p.ct0&&a[i-1].ct>=tE&&a[i-1].ct=tE&&a[i+1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tVE=m+1.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tVE;\n const prev=i>0&&a[i-1].ct>=tVE;\n const next=i=tVE;\n return [p.ts,(here||prev||next)?p.ct:null];\n});" + }, + { + "entity": "sun.sun", + "name": "Keine Daten", "type": "line", - "extend_to": false, - "data_generator": "return entity.attributes.data.map((entry) => {\n return [new Date(entry.start_time), entry.price_per_kwh];\n});\n", - "curve": "stepline", - "color_threshold": [ - { - "value": 0.1, - "color": "blue" - }, - { - "value": 0.2, - "color": "cyan" - }, - { - "value": 0.25, - "color": "green" - }, - { - "value": 0.3, - "color": "yellow" - }, - { - "value": 0.35, - "color": "orange" - }, - { - "value": 0.4, - "color": "red" - } - ] + "color": "#546e7a", + "yaxis_id": "price", + "stroke_width": 1, + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const ed=new Date(); ed.setDate(ed.getDate()+3); ed.setHours(0,0,0,0); const es=ed.getFullYear()+'-'+String(ed.getMonth()+1).padStart(2,'0')+'-'+String(ed.getDate()).padStart(2,'0')+' 00:00:00'; const r=await hass.callWS({type:'call_service',domain:'tibber',service:'get_prices',return_response:true,service_data:{end:es}}); const prices=r.response.prices.Zuhause; const known=new Set(prices.map(p=>new Date(p.start_time).getTime())); const cts=prices.map(p=>Math.round(p.price*10000)/100); const avg=Math.round(cts.reduce((x,y)=>x+y,0)/cts.length*10)/10; const start=new Date(); start.setHours(0,0,0,0); const result=[]; for(let i=0;i<192;i++){\n const ts=start.getTime()+i*15*60*1000;\n result.push([ts,known.has(ts)?null:avg]);\n} return result;" } ] }, @@ -1840,6 +2032,271 @@ } ], "hours_to_show": 0.02 + }, + { + "type": "custom:config-template-card", + "variables": { + "v_offset": "states['binary_sensor.zuhause_morgige_daten_verfugbar'].state === 'on' ? '+1d' : '+0d'", + "v_yaxis_min": "states['sensor.zuhause_diagramm_metadaten'].attributes.yaxis_min", + "v_yaxis_max": "states['sensor.zuhause_diagramm_metadaten'].attributes.yaxis_max" + }, + "entities": [ + "binary_sensor.zuhause_morgige_daten_verfugbar", + "sensor.zuhause_diagramm_metadaten" + ], + "card": { + "type": "custom:apexcharts-card", + "update_interval": "5m", + "header": { + "show": true, + "title": "Preisniveau", + "show_states": false + }, + "apex_config": { + "chart": { + "animations": { + "enabled": false + }, + "toolbar": { + "show": true, + "tools": { + "zoom": true, + "pan": true + } + }, + "zoom": { + "enabled": true + } + }, + "stroke": { + "curve": "stepline" + }, + "fill": { + "type": "gradient", + "opacity": 0.45, + "gradient": { + "shade": "light", + "type": "vertical", + "shadeIntensity": 0.2, + "opacityFrom": [ + 0.5, + 0.7, + 0.7, + 0.7, + 0.7, + 0.7 + ], + "opacityTo": 0.25, + "stops": [ + 50, + 100 + ] + } + }, + "dataLabels": { + "enabled": false + }, + "legend": { + "show": true, + "position": "bottom", + "horizontalAlign": "center", + "markers": { + "size": 0 + }, + "itemMargin": { + "horizontal": 15 + } + }, + "grid": { + "show": true, + "borderColor": "rgba(144, 164, 174, 0.35)", + "strokeDashArray": 0, + "xaxis": { + "lines": { + "show": false + } + }, + "yaxis": { + "lines": { + "show": true + } + } + }, + "markers": { + "size": 0, + "hover": { + "size": 3 + }, + "colors": "#ff0000", + "fillOpacity": 0.5, + "strokeWidth": 5, + "strokeColors": "#ff0000", + "strokeOpacity": 0.15, + "showNullDataPoints": false + }, + "tooltip": { + "enabled": true, + "shared": true, + "enabledOnSeries": [ + 2, + 3, + 4, + 5, + 6 + ], + "marker": { + "show": false + }, + "x": { + "show": false + } + } + }, + "yaxis": [ + { + "id": "price", + "min": "${v_yaxis_min}", + "max": "${v_yaxis_max}", + "apex_config": { + "title": { + "text": "ct/kWh" + }, + "decimalsInFloat": 0, + "forceNiceScale": true, + "showAlways": true, + "tickAmount": 4 + } + }, + { + "id": "highlight", + "min": 0, + "max": 1, + "show": false, + "opposite": true, + "apex_config": { + "forceNiceScale": true, + "tickAmount": 4 + } + } + ], + "now": { + "show": true, + "color": "#8e24aa", + "label": "🕒 LIVE" + }, + "all_series_config": { + "float_precision": 2 + }, + "series": [ + { + "entity": "sensor.zuhause_mindestpreis_heute", + "name": "▼ Bestpreis-Zeitraum", + "type": "area", + "color": "rgba(46, 204, 113, 0.05)", + "yaxis_id": "highlight", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": true + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', period_filter: 'best_price', resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true } }); const originalData = response.response.data; return originalData.map((point, i) => { const result = [point[0], point[1] === null ? null : 1]; result.originalPrice = point[1]; return result; });", + "stroke_width": 0 + }, + { + "entity": "sensor.zuhause_mindestpreis_heute", + "name": "▲ Spitzenpreis-Zeitraum", + "type": "area", + "color": "rgba(231, 76, 60, 0.06)", + "yaxis_id": "highlight", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": true, + "hidden_by_default": true + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', period_filter: 'peak_price', resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true } }); const originalData = response.response.data; return originalData.map((point, i) => { const result = [point[0], point[1] === null ? null : 1]; result.originalPrice = point[1]; return result; });", + "stroke_width": 0 + }, + { + "entity": "sensor.zuhause_mindestpreis_heute", + "name": "Sehr günstig", + "type": "area", + "color": "#2ecc71", + "yaxis_id": "price", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', level_filter: ['VERY_CHEAP'], resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true, connect_segments: true } }); return response.response.data;", + "stroke_width": 1.5 + }, + { + "entity": "sensor.zuhause_mindestpreis_heute", + "name": "Günstig", + "type": "area", + "color": "#27ae60", + "yaxis_id": "price", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', level_filter: ['CHEAP'], resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true, connect_segments: true } }); return response.response.data;", + "stroke_width": 1.5 + }, + { + "entity": "sensor.zuhause_preis_heute", + "name": "Normal", + "type": "area", + "color": "#f1c40f", + "yaxis_id": "price", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', level_filter: ['NORMAL'], resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true, connect_segments: true } }); return response.response.data;", + "stroke_width": 1.5 + }, + { + "entity": "sensor.zuhause_hochstpreis_heute", + "name": "Teuer", + "type": "area", + "color": "#e67e22", + "yaxis_id": "price", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', level_filter: ['EXPENSIVE'], resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true, connect_segments: true } }); return response.response.data;", + "stroke_width": 1.5 + }, + { + "entity": "sensor.zuhause_hochstpreis_heute", + "name": "Sehr teuer", + "type": "area", + "color": "#e74c3c", + "yaxis_id": "price", + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const response = await hass.callWS({ type: 'call_service', domain: 'tibber_prices', service: 'get_chartdata', return_response: true, service_data: { entry_id: '01KRH5M2Q1R4A4JVTBYN9KZZ70', level_filter: ['VERY_EXPENSIVE'], resolution: 'interval', output_format: 'array_of_arrays', insert_nulls: 'segments', subunit_currency: true, connect_segments: true } }); return response.response.data;", + "stroke_width": 1.5 + } + ], + "experimental": { + "hidden_by_default": true + }, + "graph_span": "48h", + "span": { + "end": "day", + "offset": "${v_offset}" + } + } } ] } diff --git a/.storage/lovelace.dashboard_spa b/.storage/lovelace.dashboard_spa index 4da92a3..d13afff 100644 --- a/.storage/lovelace.dashboard_spa +++ b/.storage/lovelace.dashboard_spa @@ -19,37 +19,25 @@ "type": "heading", "heading": "Status & Steuerung" }, - { - "type": "custom:mushroom-template-card", - "primary": "{% set ph = states('sensor.whirlpool_ph') | float(0) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(0) %} {% set online = is_state('binary_sensor.isonline_2', 'on') %} {% if not online %} Offline ⚠️ {% elif ph >= 7.0 and ph <= 7.6 and orp >= 650 %} Badespaß bereit! 🛁 {% else %} Wasser prüfen! ⚠️ {% endif %}", - "secondary": "{% set temp = states('sensor.spa_current_temperature') | float | round(1) %} {% set ziel = states('sensor.spa_desired_temperature') | float | round(1) %} {% set rate = states('sensor.whirlpool_heizrate') | float(0) | round(2) %} {{ temp }}°C → Ziel {{ ziel }}°C {%- if rate > 0 %} ↑ {{ rate }} °C/min {%- elif rate < 0 %} ↓ {{ rate | abs }} °C/min {%- endif %}", - "icon": "mdi:hot-tub", - "icon_color": "{% set ph = states('sensor.whirlpool_ph') | float(0) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(0) %} {% if not is_state('binary_sensor.isonline_2', 'on') %} grey {% elif ph >= 7.0 and ph <= 7.6 and orp >= 650 %} green {% elif (ph < 6.8 or ph > 7.9) or orp < 550 %} red {% else %} orange {% endif %}", - "vertical": true, - "grid_options": { - "columns": 12, - "rows": 2 - } - }, { "type": "custom:mushroom-chips-card", "chips": [ { "type": "template", "icon": "mdi:ph", - "content": "{{ states(\"sensor.whirlpool_ph\") | float | round(1) }}", + "content": "{{ states('sensor.whirlpool_ph') | float | round(1) }}", "icon_color": "blue" }, { "type": "template", "icon": "mdi:water-percent", - "content": "{{ states(\"sensor.whirlpool_oxydo_reduktionspotenzial\") | int }} mV", + "content": "{{ states('sensor.whirlpool_oxydo_reduktionspotenzial') | int }} mV", "icon_color": "purple" }, { "type": "template", "icon": "mdi:flash", - "content": "{{ states(\"sensor.whirlpool_leistung\") | int(0) }} W", + "content": "{{ states('sensor.whirlpool_leistung') | int(0) }} W", "icon_color": "amber" }, { @@ -60,22 +48,32 @@ ], "alignment": "center" }, + { + "type": "custom:mushroom-template-card", + "primary": "{% set ph = states('sensor.whirlpool_ph') | float(0) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(0) %} {% set online = is_state('binary_sensor.isonline_2', 'on') %} {% if not online %} Offline ⚠️ {% elif ph >= 7.0 and ph <= 7.6 and orp >= 550 and orp < 650 %} Badespaß bereit! 🛁 {% else %} Wasser prüfen! ⚠️ {% endif %}", + "secondary": "{% set temp = states('sensor.spa_current_temperature') | float | round(1) %} {% set ziel = states('sensor.spa_desired_temperature') | float | round(1) %} {% set rate = states('sensor.whirlpool_heizrate') | float(0) | round(2) %} {{ temp }}°C → Ziel {{ ziel }}°C {%- if rate > 0 %} ↑ {{ rate }} °C/min {%- elif rate < 0 %} ↓ {{ rate | abs }} °C/min {%- endif %}", + "icon": "mdi:hot-tub", + "icon_color": "{% set ph = states('sensor.whirlpool_ph') | float(0) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(0) %} {% if not is_state('binary_sensor.isonline_2', 'on') %} grey {% elif ph >= 7.0 and ph <= 7.6 and orp <= 650 %} green {% elif (ph < 6.8 or ph > 7.9) or orp < 550 %} red {% else %} orange {% endif %}", + "vertical": true, + "grid_options": { + "columns": 12, + "rows": 2 + } + }, { "type": "custom:mushroom-climate-card", "entity": "climate.spa_thermostat", - "name": "Temperatur einstellen", + "name": "Temperatur", "show_temperature_control": true, + "fill_container": false, + "tap_action": { + "action": "more-info" + }, "layout": "horizontal" }, { "type": "horizontal-stack", "cards": [ - { - "type": "custom:mushroom-entity-card", - "entity": "switch.whirlpool", - "name": "Strom", - "icon": "mdi:power" - }, { "type": "custom:mushroom-entity-card", "entity": "switch.spa_pump", @@ -111,33 +109,16 @@ ] }, { - "type": "horizontal-stack", - "cards": [ - { - "type": "custom:mushroom-select-card", - "entity": "select.spa_heater_mode", - "name": "Heizmodus", - "icon": "mdi:fire" - }, - { - "type": "custom:mushroom-select-card", - "entity": "select.spa_temperature_range", - "name": "Temp.-Bereich", - "icon": "mdi:thermometer-lines" - } - ] + "type": "heading", + "heading": "Zeitpläne & Wartung" }, { - "type": "custom:mushroom-template-card", - "primary": "{% set alerts = states('sensor.spa_total_alerts') | int(0) %} {% if alerts == 0 %} Keine Störungen {% else %} {{ alerts }} Warnung(en) aktiv {% endif %}", - "secondary": "{{ states(\"sensor.spa_fault_message\") }}", - "icon": "{% if states('sensor.spa_total_alerts') | int(0) > 0 %} mdi:alert-circle {% else %} mdi:check-circle {% endif %}", - "icon_color": "{% if states('sensor.spa_total_alerts') | int(0) > 0 %} red {% else %} green {% endif %}", - "fill_container": true, - "grid_options": { - "columns": 12, - "rows": 1 - } + "type": "custom:scheduler-card", + "include": [ + "climate.spa_thermostat", + "switch.spa_pump" + ], + "title": "Whirlpool Automatik" }, { "type": "heading", @@ -147,15 +128,17 @@ "type": "custom:mushroom-light-card", "entity": "light.ruheplatz_lichterkette", "name": "Lichterkette", - "show_brightness_control": true, - "use_light_color": true + "show_brightness_control": true }, { "type": "custom:mushroom-light-card", "entity": "light.ruheplatz_wegbeleuchtung", "name": "Wegbeleuchtung", - "show_brightness_control": true, - "use_light_color": true + "show_brightness_control": true + }, + { + "type": "markdown", + "content": "ICO Kalibrierung: 08.05.2026" } ] }, @@ -164,7 +147,7 @@ "cards": [ { "type": "heading", - "heading": "Wasseranalyse (24h)" + "heading": "Wasseranalyse & Trends" }, { "type": "custom:apexcharts-card", @@ -178,18 +161,23 @@ { "id": "ph", "min": 6.5, - "max": 8, + "max": 8.5, "decimals": 1, "apex_config": { "tickAmount": 3 - } + }, + "align_to": 1 }, { "id": "orp", "min": 400, - "max": 900, + "max": 700, "opposite": true, - "decimals": 0 + "decimals": 0, + "apex_config": { + "tickAmount": 3 + }, + "align_to": 100 } ], "series": [ @@ -197,147 +185,65 @@ "entity": "sensor.whirlpool_ph", "name": "pH", "yaxis_id": "ph", - "color": "#2196f3", - "stroke_width": 3 + "color": "#2196f3" }, { "entity": "sensor.whirlpool_oxydo_reduktionspotenzial", "name": "ORP", "yaxis_id": "orp", - "color": "#9c27b0", - "stroke_width": 3 + "color": "#9c27b0" } ], "apex_config": { + "stroke": { + "curve": "smooth" + }, "annotations": { - "position": "back", "yaxis": [ { "y": 7, "y2": 7.6, - "y_axis_id": "ph", - "fillColor": "#4CAF50", - "opacity": 0.15, + "borderColor": "#2196f3", + "fillColor": "#2196f3", + "opacity": 0.12, "label": { - "text": "IDEAL" + "text": "pH", + "style": { + "background": "#2196f3", + "color": "#fff" + } + } + }, + { + "y": 650, + "y2": 550, + "yAxisIndex": 1, + "borderColor": "#9c27b0", + "fillColor": "#9c27b0", + "opacity": 0.12, + "label": { + "text": "ORP", + "style": { + "background": "#9c27b0", + "color": "#fff" + } } } ] } } }, - { - "type": "custom:apexcharts-card", - "graph_span": "24h", - "header": { - "show": true, - "title": "Temperaturverlauf", - "show_states": true, - "colorize_states": true - }, - "series": [ - { - "entity": "sensor.spa_current_temperature", - "name": "Ist", - "color": "#f44336", - "stroke_width": 3 - }, - { - "entity": "sensor.spa_desired_temperature", - "name": "Soll", - "color": "#ff9800", - "stroke_width": 2, - "curve": "stepline" - } - ] - }, - { - "type": "custom:apexcharts-card", - "graph_span": "24h", - "header": { - "show": true, - "title": "Verbrauch (W)", - "show_states": true, - "colorize_states": true - }, - "series": [ - { - "entity": "sensor.whirlpool_leistung", - "name": "Gesamtleistung", - "color": "#FF5722", - "stroke_width": 2, - "type": "area" - } - ] - }, - { - "type": "heading", - "heading": "Energieverbrauch" - }, - { - "type": "horizontal-stack", - "cards": [ - { - "type": "custom:mushroom-template-card", - "primary": "{{ states('sensor.spa_heater_energy') | float | round(2) }} kWh", - "secondary": "Heizung", - "icon": "mdi:fire", - "icon_color": "red" - }, - { - "type": "custom:mushroom-template-card", - "primary": "{{ states('sensor.spa_pump_energy') | float | round(2) }} kWh", - "secondary": "Düsen", - "icon": "mdi:pump", - "icon_color": "blue" - }, - { - "type": "custom:mushroom-template-card", - "primary": "{{ states('sensor.spa_circulation_pump_energy') | float | round(2) }} kWh", - "secondary": "Zirkulation", - "icon": "mdi:water-sync", - "icon_color": "cyan" - } - ] - }, - { - "type": "heading", - "heading": "Ondilo ICO Sensor" - }, - { - "type": "horizontal-stack", - "cards": [ - { - "type": "custom:mushroom-template-card", - "primary": "{{ states(\"sensor.whirlpool_batterie\") }} %", - "secondary": "Sensor Akku", - "icon": "mdi:battery-bluetooth", - "icon_color": "{% set b = states('sensor.whirlpool_batterie') | int(100) %} {% if b < 20 %} red {% elif b < 50 %} orange {% else %} green {% endif %}" - }, - { - "type": "custom:mushroom-template-card", - "primary": "{{ states(\"sensor.whirlpool_rssi\") }} dBm", - "secondary": "Signal", - "icon": "mdi:wifi", - "icon_color": "{% set r = states('sensor.whirlpool_rssi') | int(-100) %} {% if r < -80 %} red {% elif r < -60 %} orange {% else %} green {% endif %}" - } - ] - } - ] - }, - { - "type": "grid", - "cards": [ { "type": "heading", "heading": "Pflege-Protokoll" }, { "type": "custom:mushroom-template-card", - "primary": "{% set last = states('input_datetime.whirlpool_letzte_wasserpflege') %} {% if last == 'unknown' or last == '' %}\n Noch kein Datum gesetzt\n{% else %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n Letzte Pflege: vor {{ days }} Tag{{ 'en' if days != 1 else '' }}\n{% endif %}", - "secondary": "{% set last = states('input_datetime.whirlpool_letzte_wasserpflege') %} {% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(700) %} {% if last != 'unknown' and last != '' %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n {% if days >= 10 %} ⚠️ Pflege überfällig!\n {% elif days >= 7 %} Pflegerunde empfohlen\n {% else %} Nächste Pflege in {{ 7 - days }} Tagen\n {% endif %}\n{% else %}\n pH + Brom + Wasserrein einmal wöchentlich\n{% endif %} {%- set ph_ok = ph >= 7.0 and ph <= 7.6 %} {%- set orp_ok = orp >= 650 and orp <= 750 %} {{ ' | pH: ✓' if ph_ok else ' | pH: ⚠️ ' ~ ph | round(1) }} {{ ' | ORP: ✓' if orp_ok else ' | ORP: ⚠️ ' ~ orp | round(0) ~ ' mV' }}", + "primary": "{% set last = states('input_datetime.whirlpool_letzte_wasserpflege') %} {% if last in ['unknown', ''] %} Datum setzen {% else %} Letzte Pflege: vor {{ ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) }} Tagen {% endif %}", + "secondary": "{% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(700) %} 🧪 pH: {{ '✓' if 7.0 <= ph <= 7.6 else '⚠️ ' ~ ph | round(1) }} 💊 Brom: {{ '✓' if orp < 650 and orp >= 550 else '⚠️ ' ~ orp | round(0) ~ ' mV' }}", "icon": "mdi:water-check", - "icon_color": "{% set last = states('input_datetime.whirlpool_letzte_wasserpflege') %} {% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(700) %} {% if last == 'unknown' or last == '' %} grey {% elif ph < 6.8 or ph > 7.9 or orp < 550 %} red {% else %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n {% if days >= 10 %} red\n {% elif days >= 7 %} orange\n {% else %} green {% endif %}\n{% endif %}", + "multiline_secondary": true, + "icon_color": "{% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% if 7.0 <= ph <= 7.6 %} green {% else %} orange {% endif %}", "fill_container": true, "grid_options": { "columns": 12, @@ -345,152 +251,89 @@ } }, { - "type": "custom:mushroom-entity-card", - "entity": "input_datetime.whirlpool_letzte_wasserpflege", - "name": "Wasserpflege – Datum setzen", - "icon": "mdi:calendar-edit" - }, - { - "type": "custom:mushroom-template-card", - "primary": "{% set last = states('input_datetime.whirlpool_letzter_kartuschenwechsel') %} {% if last == 'unknown' or last == '' %}\n Noch kein Datum gesetzt\n{% else %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n Letzter Kartuschenwechsel: vor {{ days }} Tag{{ 'en' if days != 1 else '' }}\n{% endif %}", - "secondary": "{% set last = states('input_datetime.whirlpool_letzter_kartuschenwechsel') %} {% set intervall = 60 %} {% if last != 'unknown' and last != '' %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n {% set rest = intervall - days %}\n {% if rest <= 0 %} ⚠️ Kartusche wechseln! ({{ days }} Tage alt)\n {% elif rest <= 14 %} Wechsel in {{ rest }} Tagen empfohlen\n {% else %} Nächster Wechsel in {{ rest }} Tagen (alle 2 Monate)\n {% endif %}\n{% else %}\n Empfehlung: alle 60 Tage bei 1–2× Nutzung/Woche\n{% endif %}", - "icon": "mdi:air-filter", - "icon_color": "{% set last = states('input_datetime.whirlpool_letzter_kartuschenwechsel') %} {% if last == 'unknown' or last == '' %} grey {% else %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n {% if days >= 60 %} red\n {% elif days >= 46 %} orange\n {% else %} green {% endif %}\n{% endif %}", - "fill_container": true, - "grid_options": { - "columns": 12, - "rows": 1 - } - }, - { - "type": "custom:mushroom-entity-card", - "entity": "input_datetime.whirlpool_letzter_kartuschenwechsel", - "name": "Kartuschenwechsel – Datum setzen", - "icon": "mdi:calendar-edit" - }, - { - "type": "custom:mushroom-template-card", - "primary": "{% set last = states('input_datetime.whirlpool_letzter_wasserwechsel') %} {% if last == 'unknown' or last == '' %}\n Noch kein Datum gesetzt\n{% else %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n Letzter Wasserwechsel: vor {{ days }} Tag{{ 'en' if days != 1 else '' }}\n{% endif %}", - "secondary": "{% set last = states('input_datetime.whirlpool_letzter_wasserwechsel') %} {% set intervall = 120 %} {% if last != 'unknown' and last != '' %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n {% set rest = intervall - days %}\n {% if rest <= 0 %} ⚠️ Wasserwechsel überfällig! ({{ days }} Tage alt)\n {% elif rest <= 21 %} Wasserwechsel in {{ rest }} Tagen planen\n {% else %} Nächster Wechsel in {{ rest }} Tagen (alle 4 Monate)\n {% endif %}\n{% else %}\n Empfehlung: alle 4 Monate bei 1–2× Nutzung/Woche\n{% endif %}", - "icon": "mdi:water-sync", - "icon_color": "{% set last = states('input_datetime.whirlpool_letzter_wasserwechsel') %} {% if last == 'unknown' or last == '' %} grey {% else %}\n {% set days = ((now().date() - strptime(last[:10], '%Y-%m-%d').date()).days) %}\n {% if days >= 120 %} red\n {% elif days >= 99 %} orange\n {% else %} green {% endif %}\n{% endif %}", - "fill_container": true, - "grid_options": { - "columns": 12, - "rows": 1 - } - }, - { - "type": "custom:mushroom-entity-card", - "entity": "input_datetime.whirlpool_letzter_wasserwechsel", - "name": "Wasserwechsel – Datum setzen", - "icon": "mdi:calendar-edit" + "type": "horizontal-stack", + "cards": [ + { + "type": "custom:mushroom-entity-card", + "entity": "input_datetime.whirlpool_letzte_wasserpflege", + "name": "Pflege erledigt", + "icon": "mdi:calendar-check" + } + ] }, { "type": "heading", - "heading": "Dosierungsempfehlung" + "heading": "Dosierung (1.000L)" }, { "type": "custom:mushroom-template-card", - "primary": "Dosierung diese Woche", - "secondary": "{% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(700) %}\n🧪 pH ({{ ph | round(1) }}): {% if ph >= 7.0 and ph <= 7.6 %} Optimal – nichts nötig. {% elif ph > 7.6 %}\n pH-Minus: ca. {{ (((ph - 7.6) / 0.1) * 10 / 1.1) | round(0) | int }} g zugeben.\n{% else %}\n pH-Plus: ca. {{ (((7.0 - ph) / 0.1) * 10) | round(0) | int }} g zugeben.\n{% endif %} Warte 4h, dann nachmessen. |\n💊 Brom ({{ orp | round(0) }} mV): {% if orp >= 650 and orp <= 750 %} Optimal – nichts nötig. {% elif orp > 750 %} Zu hoch – keine Tabletten, Deckel öffnen. {% elif orp < 600 %} 3–4 Tabletten in Dosierschwimmer. {% else %} 1–2 Tabletten nachlegen. {% endif %} |\n🫧 Wasserrein (Bayrol): 10 ml auf 1.500 l wöchentlich zugeben, Pumpe dabei 30 min laufen lassen.", - "icon": "mdi:flask-outline", - "icon_color": "{% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% set orp = states('sensor.whirlpool_oxydo_reduktionspotenzial') | float(700) %} {% if ph < 6.8 or ph > 7.9 or orp < 550 %} red {% elif (ph < 7.0 or ph > 7.6) or (orp < 650 or orp > 750) %} orange {% else %} green {% endif %}", + "primary": "Aktueller Dosiervorschlag", + "secondary": "{% set ph = states('sensor.whirlpool_ph') | float(7.2) %} {% if ph > 7.6 %}\n 🧪 pH: {{ ((ph - 7.4) / 0.1 * 10) | round(0) }}g pH-Minus\n{% elif ph < 7.0 %}\n 🧪 pH: {{ ((7.2 - ph) / 0.1 * 10) | round(0) }}g pH-Plus\n{% else %}\n 🧪 pH: OK ✓\n{% endif %}\n💊 Brom: {{ '3-4 Tabs nachlegen' if states('sensor.whirlpool_oxydo_reduktionspotenzial')|float < 600 else 'OK ✓' }}", + "icon": "mdi:flask-plus", + "icon_color": "orange", + "multiline_secondary": true, "fill_container": true, "grid_options": { "columns": 12, - "rows": 4 + "rows": 2 } }, { "type": "custom:mushroom-template-card", - "primary": "Nach Wasserwechsel – Erstbefüllung", - "secondary": "① 30 g Aktivsauerstoff (Bayrol Soft & Easy) direkt zugeben | ② Pumpe 1h laufen lassen | ③ pH messen & korrigieren (Ziel 7,0–7,6) | ④ Brom-Tabletten in Dosierschwimmer legen | ⑤ Nach 24h nochmals alle Werte prüfen", - "icon": "mdi:flask", - "icon_color": "blue", - "fill_container": true, - "grid_options": { - "columns": 12, - "rows": 3 - } - }, - { - "type": "custom:mushroom-template-card", - "primary": "Wöchentliche Pflege-Checkliste", - "secondary": "① pH messen & ggf. korrigieren (Ziel 7,0–7,6) | ② Brom-Tabletten im Dosierschwimmer prüfen & ggf. nachlegen | ③ 10 ml Wasserrein (Bayrol) zugeben | ④ Pumpe mind. 30 min laufen lassen | ⑤ Filtration läuft? (mind. 4–6h/Tag) | ⑥ Abdeckung nach Nutzung schließen", - "icon": "mdi:clipboard-check-outline", + "primary": "Samstag Vormittag: Routine", + "secondary": "① 1 Beutel Wasserrein (Granulat)\n② 10ml Kristall-Klar (Flüssig)\n③ Brom-Tabletten prüfen (3-4 Stk)\n④ TA-Wert prüfen (Alka-Plus?)\n", + "icon": "mdi:calendar-star", "icon_color": "teal", + "multiline_secondary": true, "fill_container": true, "grid_options": { "columns": 12, "rows": 3 } + }, + { + "type": "custom:mushroom-template-card", + "primary": "Neu-Befüllung / Erstbefüllung", + "secondary": "① 25ml Kalkex (Flüssig)\n② pH auf 7,2 einstellen\n③ 1 Beutel Wasserrein (Schock)\n④ 4 Brom-Tabletten (Schwimmer)\n", + "icon": "mdi:waves", + "icon_color": "blue", + "multiline_secondary": true, + "fill_container": true, + "grid_options": { + "columns": 12, + "rows": 2 + } + }, + { + "type": "horizontal-stack", + "cards": [ + { + "type": "custom:mushroom-entity-card", + "entity": "input_datetime.whirlpool_letzter_kartuschenwechsel", + "name": "Filterwechsel", + "icon": "mdi:filter-cog" + } + ] + }, + { + "type": "horizontal-stack", + "cards": [ + { + "type": "custom:mushroom-entity-card", + "entity": "input_datetime.whirlpool_letzter_wasserwechsel", + "name": "Wasserwechsel", + "icon": "mdi:water-sync" + } + ] } ] }, { "type": "grid", - "cards": [ - { - "type": "heading", - "heading": "Filterprogramme" - }, - { - "type": "horizontal-stack", - "cards": [ - { - "type": "custom:mushroom-select-card", - "entity": "select.spa_filter_time_1", - "name": "Filterzeit 1", - "icon": "mdi:clock-start" - }, - { - "type": "custom:mushroom-select-card", - "entity": "select.spa_filter_duration_1", - "name": "Dauer 1", - "icon": "mdi:timer" - } - ] - }, - { - "type": "horizontal-stack", - "cards": [ - { - "type": "custom:mushroom-select-card", - "entity": "select.spa_filter_time_2", - "name": "Filterzeit 2", - "icon": "mdi:clock-start" - }, - { - "type": "custom:mushroom-select-card", - "entity": "select.spa_filter_duration_2", - "name": "Dauer 2", - "icon": "mdi:timer" - } - ] - }, - { - "type": "custom:mushroom-entity-card", - "entity": "switch.whirlpool_filterzyklus_2_aktivieren", - "name": "Filterzyklus 2 aktiv", - "icon": "mdi:filter-check" - }, - { - "type": "heading", - "heading": "Zeitpläne & Automatik" - }, - { - "type": "custom:scheduler-card", - "include": [ - "climate.spa_thermostat", - "switch.spa_pump", - "switch.whirlpool" - ], - "title": "Whirlpool Automatik" - } - ] + "cards": [] } - ] + ], + "cards": [] } ] } diff --git a/.storage/lovelace.lovelace b/.storage/lovelace.lovelace index 0546dfe..6abfe1b 100644 --- a/.storage/lovelace.lovelace +++ b/.storage/lovelace.lovelace @@ -58,85 +58,269 @@ }, { "type": "custom:apexcharts-card", + "update_interval": "5m", + "graph_span": "48h", + "span": { + "start": "day" + }, + "experimental": { + "hidden_by_default": true + }, "header": { "show": true, - "show_states": false, - "standard_format": true, - "disable_actions": true + "title": "Preisniveau", + "show_states": false + }, + "now": { + "show": true, + "color": "#ffffff" + }, + "all_series_config": { + "float_precision": 2 }, "apex_config": { + "chart": { + "animations": { + "enabled": false + }, + "toolbar": { + "show": false + }, + "zoom": { + "enabled": false + } + }, + "stroke": { + "curve": "stepline", + "dashArray": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4 + ] + }, + "fill": { + "type": "gradient", + "opacity": 0.45, + "gradient": { + "shade": "light", + "type": "vertical", + "shadeIntensity": 0.2, + "opacityFrom": [ + 0.5, + 0.7, + 0.7, + 0.7, + 0.7, + 0.7, + 0.7, + 0 + ], + "opacityTo": 0.25, + "stops": [ + 50, + 100 + ] + } + }, + "dataLabels": { + "enabled": false + }, "legend": { - "show": false + "show": true, + "position": "bottom", + "horizontalAlign": "center", + "markers": { + "size": 0 + }, + "itemMargin": { + "horizontal": 15 + } + }, + "grid": { + "show": true, + "borderColor": "rgba(144, 164, 174, 0.35)", + "strokeDashArray": 0, + "xaxis": { + "lines": { + "show": false + } + }, + "yaxis": { + "lines": { + "show": true + } + } + }, + "markers": { + "size": 0, + "hover": { + "size": 3 + }, + "showNullDataPoints": false + }, + "tooltip": { + "enabled": true, + "shared": true, + "enabledOnSeries": [ + 2, + 3, + 4, + 5, + 6 + ], + "marker": { + "show": false + }, + "x": { + "show": false + } } }, "yaxis": [ { "id": "price", - "min": "~0.1", - "max": "~0.4", - "align_to": 1, - "decimals": 2 + "min": 0, + "max": 40, + "apex_config": { + "title": { + "text": "ct/kWh" + }, + "decimalsInFloat": 0, + "forceNiceScale": true, + "showAlways": true, + "tickAmount": 4 + } }, { - "id": "energy", + "id": "highlight", + "min": 0, + "max": 1, + "show": false, "opposite": true, - "align_to": 100, - "decimals": 0 + "apex_config": { + "forceNiceScale": true, + "tickAmount": 4 + } } ], - "chart_type": "line", - "show": { - "last_updated": true - }, - "graph_span": "1.5d", - "span": { - "start": "day" - }, - "now": { - "show": true, - "label": "Jetzt" - }, - "experimental": { - "color_threshold": true - }, "series": [ { - "entity": "sensor.epex_spot_data_total_price", - "yaxis_id": "price", - "stroke_width": 2, + "entity": "sun.sun", + "name": "▼ Bestpreis-Zeitraum", + "type": "area", + "color": "rgba(46, 204, 113, 0.05)", + "yaxis_id": "highlight", + "stroke_width": 0, "show": { - "legend_value": false + "legend_value": false, + "in_header": false, + "in_legend": true }, + "data_generator": "const ed=new Date(); ed.setDate(ed.getDate()+3); ed.setHours(0,0,0,0); const es=ed.getFullYear()+'-'+String(ed.getMonth()+1).padStart(2,'0')+'-'+String(ed.getDate()).padStart(2,'0')+' 00:00:00'; const r=await hass.callWS({type:'call_service',domain:'tibber',service:'get_prices',return_response:true,service_data:{end:es}}); const a=r.response.prices.Zuhause.map(p=>({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tC=m-0.5*sd; return a.map(p=>[p.ts,p.ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tE=m+0.5*sd; return a.map(p=>[p.ts,p.ct>=tE?1:null]);" + }, + { + "entity": "sun.sun", + "name": "Sehr günstig", + "type": "area", + "color": "#2ecc71", + "yaxis_id": "price", + "stroke_width": 1.5, + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const ed=new Date(); ed.setDate(ed.getDate()+3); ed.setHours(0,0,0,0); const es=ed.getFullYear()+'-'+String(ed.getMonth()+1).padStart(2,'0')+'-'+String(ed.getDate()).padStart(2,'0')+' 00:00:00'; const r=await hass.callWS({type:'call_service',domain:'tibber',service:'get_prices',return_response:true,service_data:{end:es}}); const a=r.response.prices.Zuhause.map(p=>({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tVC=m-1.5*sd; return a.map((p,i)=>{\n const here=p.ct0&&a[i-1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tVC=m-1.5*sd; const tC=m-0.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tVC&&p.ct0&&a[i-1].ct>=tVC&&a[i-1].ct=tVC&&a[i+1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tC=m-0.5*sd; const tE=m+0.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tC&&p.ct0&&a[i-1].ct>=tC&&a[i-1].ct=tC&&a[i+1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tE=m+0.5*sd; const tVE=m+1.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tE&&p.ct0&&a[i-1].ct>=tE&&a[i-1].ct=tE&&a[i+1].ct({ts:new Date(p.start_time).getTime(),ct:Math.round(p.price*10000)/100})); const cts=a.map(p=>p.ct); const m=cts.reduce((x,y)=>x+y,0)/cts.length; const sd=Math.sqrt(cts.map(c=>(c-m)**2).reduce((x,y)=>x+y,0)/cts.length); const tVE=m+1.5*sd; return a.map((p,i)=>{\n const here=p.ct>=tVE;\n const prev=i>0&&a[i-1].ct>=tVE;\n const next=i=tVE;\n return [p.ts,(here||prev||next)?p.ct:null];\n});" + }, + { + "entity": "sun.sun", + "name": "Keine Daten", "type": "line", - "extend_to": false, - "data_generator": "return entity.attributes.data.map((entry) => {\n return [new Date(entry.start_time), entry.price_per_kwh];\n});\n", - "curve": "stepline", - "color_threshold": [ - { - "value": 0.1, - "color": "blue" - }, - { - "value": 0.2, - "color": "cyan" - }, - { - "value": 0.25, - "color": "green" - }, - { - "value": 0.3, - "color": "yellow" - }, - { - "value": 0.35, - "color": "orange" - }, - { - "value": 0.4, - "color": "red" - } - ] + "color": "#546e7a", + "yaxis_id": "price", + "stroke_width": 1, + "show": { + "legend_value": false, + "in_header": false, + "in_legend": false + }, + "data_generator": "const ed=new Date(); ed.setDate(ed.getDate()+3); ed.setHours(0,0,0,0); const es=ed.getFullYear()+'-'+String(ed.getMonth()+1).padStart(2,'0')+'-'+String(ed.getDate()).padStart(2,'0')+' 00:00:00'; const r=await hass.callWS({type:'call_service',domain:'tibber',service:'get_prices',return_response:true,service_data:{end:es}}); const prices=r.response.prices.Zuhause; const known=new Set(prices.map(p=>new Date(p.start_time).getTime())); const cts=prices.map(p=>Math.round(p.price*10000)/100); const avg=Math.round(cts.reduce((x,y)=>x+y,0)/cts.length*10)/10; const start=new Date(); start.setHours(0,0,0,0); const result=[]; for(let i=0;i<192;i++){\n const ts=start.getTime()+i*15*60*1000;\n result.push([ts,known.has(ts)?null:avg]);\n} return result;" } ] }, @@ -203,8 +387,44 @@ }, "grid": { "entity": { - "consumption": "sensor.powerocean_hj37zdh5zg5w0109_netz_zu_haus", - "production": "sensor.powerocean_hj37zdh5zg5w0109_solar_zu_netz" + "0": "s", + "1": "e", + "2": "n", + "3": "s", + "4": "o", + "5": "r", + "6": ".", + "7": "t", + "8": "i", + "9": "b", + "10": "b", + "11": "e", + "12": "r", + "13": "_", + "14": "p", + "15": "u", + "16": "l", + "17": "s", + "18": "e", + "19": "_", + "20": "z", + "21": "u", + "22": "h", + "23": "a", + "24": "u", + "25": "s", + "26": "e", + "27": "_", + "28": "l", + "29": "e", + "30": "i", + "31": "s", + "32": "t", + "33": "u", + "34": "n", + "35": "g", + "consumption": "sensor.tibber_pulse_zuhause_leistung", + "production": "sensor.tibber_pulse_zuhause_einspeiseleistung" }, "secondary_info": {}, "use_metadata": false, @@ -213,7 +433,7 @@ "display_state": "two_way" }, "solar": { - "entity": "sensor.powerocean_hj37zdh5zg5w0109_solarertrag_mppt", + "entity": "sensor.powerocean_hj37zdh5zg5w0109_solar_gesamtleistung", "display_zero_state": true, "secondary_info": {}, "color_value": false, @@ -246,7 +466,7 @@ "secondary_info": {} }, { - "entity": "sensor.charger_ac31zeh4ag130052_evpwr", + "entity": "sensor.charger_ac31zeh4ag130052_ladebox_leistung", "secondary_info": {}, "name": "Wallbox", "icon": "mdi:car", @@ -302,16 +522,6 @@ "icon": "mdi:water-alert", "icon_color": "{{ 'red' if is_state('binary_sensor.technikraum_wassermelder_water_leak','on')\n or is_state('binary_sensor.wc_wassermelder_water_leak','on')\n or is_state('binary_sensor.kuche_wassermelder_water_leak','on')\n else 'green' }}\n", "content": "{% if is_state('binary_sensor.technikraum_wassermelder_water_leak','on') %}\n Wasser – Technikraum!\n{% elif is_state('binary_sensor.wc_wassermelder_water_leak','on') %}\n Wasser – WC!\n{% elif is_state('binary_sensor.kuche_wassermelder_water_leak','on') %}\n Wasser – Küche!\n{% else %}\n Trocken\n{% endif %}\n" - }, - { - "type": "template", - "icon": "mdi:heat-pump-outline", - "icon_color": "{{ 'red' if is_state('binary_sensor.nibe_s1255_6_e_em_3x400v_alarm','on')\n else 'green' }}\n", - "content": "{{ 'WP – Alarm!' if is_state('binary_sensor.nibe_s1255_6_e_em_3x400v_alarm','on')\n else 'WP ok' }}\n", - "tap_action": { - "action": "more-info", - "entity": "binary_sensor.nibe_s1255_6_e_em_3x400v_alarm" - } } ] } @@ -425,10 +635,72 @@ "hide_time_range": true, "use_summary": false }, + { + "type": "custom:mushroom-title-card", + "title": "🏊 Whirlpool" + }, + { + "type": "custom:mushroom-climate-card", + "entity": "climate.spa_thermostat", + "name": "Whirlpool", + "show_temperature_control": true, + "hvac_modes": [ + "heat", + "off" + ], + "fill_container": true, + "grid_options": { + "columns": 6, + "rows": 2 + }, + "tap_action": { + "action": "more-info" + } + }, + { + "type": "custom:mushroom-chips-card", + "chips": [ + { + "type": "template", + "icon": "mdi:ph", + "content": "{{ states('sensor.whirlpool_ph') | float | round(1) }}", + "icon_color": "blue" + }, + { + "type": "template", + "icon": "mdi:water-percent", + "content": "{{ states('sensor.whirlpool_oxydo_reduktionspotenzial') | int }} mV", + "icon_color": "purple" + } + ], + "alignment": "center", + "grid_options": { + "columns": 6, + "rows": 1 + } + }, { "type": "custom:mushroom-title-card", "title": "♨️ Wärme & Wasser" }, + { + "type": "custom:mushroom-climate-card", + "entity": "climate.climate_system_s1", + "name": "Heizung", + "show_temperature_control": true, + "hvac_modes": [], + "fill_container": true, + "grid_options": { + "columns": 6, + "rows": 2 + }, + "tap_action": { + "action": "more-info" + }, + "icon": "mdi:heat-pump", + "layout": "vertical", + "collapsible_controls": true + }, { "type": "custom:mushroom-chips-card", "alignment": "center", @@ -449,52 +721,16 @@ "icon": "mdi:gauge-full" }, { - "type": "entity", - "entity": "climate.climate_system_s1", - "icon": "mdi:heat-pump-outline" - }, - { - "type": "entity", - "icon": "mdi:heat-pump-outline" + "type": "template", + "icon": "mdi:heat-pump-outline", + "icon_color": "{{ 'red' if is_state('binary_sensor.nibe_s1255_6_e_em_3x400v_alarm','on')\n else 'green' }}\n", + "content": "{{ 'WP – Alarm!' if is_state('binary_sensor.nibe_s1255_6_e_em_3x400v_alarm','on')\n else 'WP ok' }}\n" } - ] - }, - { - "type": "custom:mushroom-title-card", - "title": "🏊 Whirlpool" - }, - { - "type": "custom:mushroom-climate-card", - "entity": "climate.spa_thermostat", - "name": "Whirlpool", - "show_temperature_control": true, - "hvac_modes": [ - "heat", - "off" ], - "fill_container": true, "grid_options": { - "columns": 12, - "rows": 2 + "columns": 6, + "rows": "auto" } - }, - { - "type": "custom:mushroom-chips-card", - "chips": [ - { - "type": "template", - "icon": "mdi:ph", - "content": "{{ states('sensor.whirlpool_ph') | float | round(1) }}", - "icon_color": "blue" - }, - { - "type": "template", - "icon": "mdi:water-percent", - "content": "{{ states('sensor.whirlpool_oxydo_reduktionspotenzial') | int }} mV", - "icon_color": "purple" - } - ], - "alignment": "center" } ] }, diff --git a/.storage/lovelace_resources b/.storage/lovelace_resources index 8600a36..5b34c95 100644 --- a/.storage/lovelace_resources +++ b/.storage/lovelace_resources @@ -21,7 +21,7 @@ }, { "id": "86772e61c8584e0081b0deefdf8bb03d", - "url": "/hacsfiles/numberbox-card/numberbox-card.js?hacstag=304967918417", + "url": "/hacsfiles/numberbox-card/numberbox-card.js?hacstag=304967918418", "type": "module" }, { @@ -54,11 +54,6 @@ "url": "/hacsfiles/spotify-card-v2/spotify-card-v2.js?hacstag=88521021411", "type": "module" }, - { - "id": "508c6e86a63e4d16acbf8e4e7aaaa10a", - "url": "/hacsfiles/mini-media-player/mini-media-player-bundle.js?hacstag=14852083811611", - "type": "module" - }, { "id": "11a657e713774a3191dd802c102c9fed", "url": "/hacsfiles/clock-weather-card/clock-weather-card.js?hacstag=522634019293", @@ -71,12 +66,12 @@ }, { "id": "6621533b33ce4101a1367464c999de79", - "url": "/hacsfiles/scheduler-card/scheduler-card.js?hacstag=2862701574017", + "url": "/hacsfiles/scheduler-card/scheduler-card.js?hacstag=2862701574018", "type": "module" }, { "id": "993a69f87387426cb5712bbe8382555e", - "url": "/hacsfiles/Bubble-Card/bubble-card.js?hacstag=680112919316", + "url": "/hacsfiles/Bubble-Card/bubble-card.js?hacstag=680112919320", "type": "module" }, { @@ -96,7 +91,12 @@ }, { "id": "c5057a3229b04e639c8a6bafcd8b9d7e", - "url": "/hacsfiles/mass-player-card/mass-player-card.js?hacstag=1043277514260", + "url": "/hacsfiles/mass-player-card/mass-player-card.js?hacstag=1043277514270", + "type": "module" + }, + { + "id": "ceb3affc0b4e4948b2699bf24ccd29a6", + "url": "/hacsfiles/config-template-card/config-template-card.js?hacstag=172177543136", "type": "module" } ] diff --git a/.storage/schedule b/.storage/schedule index efde2a4..9e54ac5 100644 --- a/.storage/schedule +++ b/.storage/schedule @@ -3,54 +3,6 @@ "minor_version": 1, "key": "schedule", "data": { - "items": [ - { - "id": "whirlpool_heizung", - "name": "Whirlpool Heizung", - "icon": "mdi:hot-tub", - "monday": [ - { - "from": "09:00:00", - "to": "16:00:00" - } - ], - "tuesday": [ - { - "from": "09:00:00", - "to": "16:00:00" - } - ], - "wednesday": [ - { - "from": "09:00:00", - "to": "16:00:00" - } - ], - "thursday": [ - { - "from": "09:00:00", - "to": "16:00:00" - } - ], - "friday": [ - { - "from": "09:00:00", - "to": "22:00:00" - } - ], - "saturday": [ - { - "from": "09:00:00", - "to": "22:00:00" - } - ], - "sunday": [ - { - "from": "09:00:00", - "to": "16:00:00" - } - ] - } - ] + "items": [] } } \ No newline at end of file diff --git a/.storage/scheduler.storage b/.storage/scheduler.storage index 9e18afa..efebb10 100644 --- a/.storage/scheduler.storage +++ b/.storage/scheduler.storage @@ -9,7 +9,7 @@ "timeslots": [ { "start": "00:00:00", - "stop": "10:00:00", + "stop": "04:00:00", "conditions": [], "condition_type": null, "track_conditions": false, @@ -25,8 +25,8 @@ ] }, { - "start": "10:00:00", - "stop": "13:00:00", + "start": "04:00:00", + "stop": "06:30:00", "conditions": [], "condition_type": null, "track_conditions": false, @@ -36,14 +36,31 @@ "entity_id": "climate.spa_thermostat", "service_data": { "hvac_mode": "heat", - "temperature": 40 + "temperature": 39 } } ] }, { - "start": "13:00:00", - "stop": "16:00:00", + "start": "06:30:00", + "stop": "11:00:00", + "conditions": [], + "condition_type": null, + "track_conditions": false, + "actions": [ + { + "service": "climate.set_temperature", + "entity_id": "climate.spa_thermostat", + "service_data": { + "hvac_mode": "heat", + "temperature": 39 + } + } + ] + }, + { + "start": "11:00:00", + "stop": "00:00:00", "conditions": [], "condition_type": null, "track_conditions": false, @@ -57,23 +74,6 @@ } } ] - }, - { - "start": "16:00:00", - "stop": "00:00:00", - "conditions": [], - "condition_type": null, - "track_conditions": false, - "actions": [ - { - "service": "climate.set_temperature", - "entity_id": "climate.spa_thermostat", - "service_data": { - "hvac_mode": "heat", - "temperature": 20 - } - } - ] } ], "weekdays": [ @@ -83,7 +83,7 @@ "end_date": null, "repeat_type": "repeat", "name": null, - "enabled": false + "enabled": true } ], "tags": [] diff --git a/automations.yaml b/automations.yaml index 34445f0..ddfd488 100644 --- a/automations.yaml +++ b/automations.yaml @@ -86,11 +86,10 @@ - sensor.karolina_tracker_batterie include_custom_actions: enable_custom_actions custom_actions: - - action: notify.send_message + - action: notify.gotify_nuclide_systems data: - title: Low battery warning - message: '{{sensors}}' - entity_id: notify.home_assistant + message: '{{all_sensors}}' + title: Battery low - id: '1726304621477' alias: Speis Sensor Light description: '' diff --git a/configuration.yaml b/configuration.yaml index c33fce8..72dbc21 100644 --- a/configuration.yaml +++ b/configuration.yaml @@ -23,7 +23,41 @@ recorder: purge_keep_days: 21 # Helper (von UI nach YAML migriert — siehe helpers/) -input_boolean: !include helpers/input_boolean.yaml -input_button: !include helpers/input_button.yaml +input_boolean: !include helpers/input_boolean.yaml +input_button: !include helpers/input_button.yaml input_datetime: !include helpers/input_datetime.yaml -timer: !include helpers/timer.yaml +timer: !include helpers/timer.yaml + +template: + - sensor: + - name: "PowerPulse EVCC Status" + unique_id: powerpulse_evcc_status + state: > + {% set s = states('sensor.charger_ac31zeh4ag130052_chargingstatus_2') %} + {% if s == 'EV_CHG_STS_AVAILABLE' %} A + {% elif s == 'EV_CHG_STS_PREPARING' %} B + {% elif s == 'EV_CHG_STS_CHARGING' %} C + {% elif s == 'EV_CHG_STS_SUSPENDED_EV' %} B + {% elif s == 'EV_CHG_STS_SUSPENDED_EVSE' %} B + {% elif s == 'EV_CHG_STS_FINISHING' %} B + {% elif s == 'EV_CHG_STS_RESERVED' %} A + {% elif s == 'EV_CHG_STS_UNAVAILABLE' %} E + {% elif s == 'EV_CHG_STS_FAULTED' %} F + {% else %} A + {% endif %} + + - name: "BYD EVCC Status" + unique_id: byd_evcc_status + state: > + {% set s = states('sensor.byd_dolphin_60_5_kwh_abrp_charging_status') %} + {% if s == 'Charging' %} C + {% elif s == 'Not Charging' %} B + {% else %} A + {% endif %} + +notify: + - name: "gotify.nuclide.systems" + platform: gotify + url: https://gotify.nuclide.systems + token: AVZyObLPatWGE_Q + verify_ssl: true # optional, default true