From fa79ffc0e6bb2f4f71c18e2345e9a01fd714855e Mon Sep 17 00:00:00 2001 From: Claus Dethlefsen Date: Wed, 22 Apr 2026 21:43:49 +0200 Subject: [PATCH] Add automated Roth floor heating control: comfort temps, night/away/vacation setbacks, seasonal valve guidance --- include/automations/varme.yaml | 14 +-- include/automations/varme_styring.yaml | 58 ++++++++++ include/automations/vinduer.yaml | 11 +- include/input/number/varme.yaml | 91 ++++++++++++++++ include/scripts/varme_styring.yaml | 140 +++++++++++++++++++++++++ include/templates/varme_ventil.yaml | 34 ++++++ 6 files changed, 327 insertions(+), 21 deletions(-) create mode 100644 include/automations/varme_styring.yaml create mode 100644 include/input/number/varme.yaml create mode 100644 include/scripts/varme_styring.yaml create mode 100644 include/templates/varme_ventil.yaml diff --git a/include/automations/varme.yaml b/include/automations/varme.yaml index a96ef74..e88cd10 100644 --- a/include/automations/varme.yaml +++ b/include/automations/varme.yaml @@ -1,12 +1,2 @@ -### Set temperature to 24 in heat mode - - alias: "Tænd varme i kontor" - trigger: - platform: time - at: "19:30:00" - action: - - service: climate.set_temperature - target: - entity_id: climate.kontor - data: - temperature: 24 - hvac_mode: heat +### Kontor-varme styres nu af script.varme_recalculate (include/scripts/varme_styring.yaml) +### Denne fil er beholdt tom for fremtidige manuelle overrides diff --git a/include/automations/varme_styring.yaml b/include/automations/varme_styring.yaml new file mode 100644 index 0000000..1381579 --- /dev/null +++ b/include/automations/varme_styring.yaml @@ -0,0 +1,58 @@ +################################################## +# Varme: Triggers der kalder script.varme_recalculate +# Scenarierne der kræver genberegning: +# - Morgen (06:30) - nat slut → komforttemp +# - Aften (22:00) - nat start → natsænkning +# - Tilstedeværelse - hjemme/væk skifter +# - Ferietilstand - ferie til/fra +# - HA genstart - genopret korrekt temp +################################################## + +- alias: "Varme - Genberegn: Morgen" + id: varme_recalc_morgen + description: "Slutter natsænkning kl. 06:30 - sætter komforttemperaturer" + trigger: + - platform: time + at: "06:30:00" + action: + - service: script.varme_recalculate + +- alias: "Varme - Genberegn: Nat" + id: varme_recalc_nat + description: "Starter natsænkning kl. 22:00" + trigger: + - platform: time + at: "22:00:00" + action: + - service: script.varme_recalculate + +- alias: "Varme - Genberegn: Tilstedeværelse" + id: varme_recalc_presence + description: "Justerer temperaturer når family_presence ændres (hjemme/væk)" + trigger: + - platform: state + entity_id: binary_sensor.family_presence + action: + # Kort forsinkelse så person-sensorer er stabile + - delay: "00:01:00" + - service: script.varme_recalculate + +- alias: "Varme - Genberegn: Ferie" + id: varme_recalc_vacation + description: "Skifter til ferie-/frosttemperatur når vacation_mode ændres" + trigger: + - platform: state + entity_id: input_boolean.vacation_mode + action: + - service: script.varme_recalculate + +- alias: "Varme - Genberegn: HA genstart" + id: varme_recalc_ha_start + description: "Genopret korrekte temperaturer efter HA genstart" + trigger: + - platform: homeassistant + event: start + action: + # Vent til integrationer er loaded + - delay: "00:01:00" + - service: script.varme_recalculate diff --git a/include/automations/vinduer.yaml b/include/automations/vinduer.yaml index ec96e5f..b14c945 100644 --- a/include/automations/vinduer.yaml +++ b/include/automations/vinduer.yaml @@ -27,12 +27,6 @@ binary_sensor.lille_bad_vindue: climate.lille_bad climate_entity: "{{ room_map[trigger.entity_id] }}" window_entity: "{{ trigger.entity_id }}" - scene_name: "vindue_varme_{{ trigger.entity_id.split('.')[1] }}" - - service: scene.create - data: - scene_id: "{{ scene_name }}" - snapshot_entities: - - "{{ climate_entity }}" - service: climate.set_hvac_mode target: entity_id: "{{ climate_entity }}" @@ -41,9 +35,8 @@ - wait_template: "{{ is_state(window_entity, 'off') }}" timeout: "04:00:00" continue_on_timeout: true - - service: scene.turn_on - target: - entity_id: "scene.{{ scene_name }}" + # Genberegn korrekt temperatur (nat/væk/komfort) efter vindue lukkes + - service: script.varme_recalculate ### Notifikation: Vindue åbner og ingen er hjemme diff --git a/include/input/number/varme.yaml b/include/input/number/varme.yaml new file mode 100644 index 0000000..22dc45e --- /dev/null +++ b/include/input/number/varme.yaml @@ -0,0 +1,91 @@ +# Komforttemperaturer per rum (Roth gulvvarme) +varme_komfort_andreas: + name: Komfort - Andreas + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 20 + icon: mdi:thermometer + +varme_komfort_daniel: + name: Komfort - Daniel + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 20 + icon: mdi:thermometer + +varme_komfort_sovevaerelse: + name: Komfort - Soveværelse + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 18 + icon: mdi:thermometer + +varme_komfort_kontor: + name: Komfort - Kontor + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 21 + icon: mdi:thermometer + +varme_komfort_gang: + name: Komfort - Gang + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 18 + icon: mdi:thermometer + +varme_komfort_forgang: + name: Komfort - Forgang + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 17 + icon: mdi:thermometer + +varme_komfort_lille_bad: + name: Komfort - Lille bad + min: 15 + max: 28 + step: 0.5 + unit_of_measurement: "°C" + initial: 22 + icon: mdi:thermometer + +# Globale sænkninger +varme_nat_saenkning: + name: Natsænkning + min: 0 + max: 8 + step: 0.5 + unit_of_measurement: "°C" + initial: 3 + icon: mdi:weather-night + +varme_vaek_saenkning: + name: Sænkning - ingen hjemme + min: 0 + max: 8 + step: 0.5 + unit_of_measurement: "°C" + initial: 3 + icon: mdi:home-export-outline + +varme_ferie_temp: + name: Ferietemperatur (frostbeskyttelse) + min: 10 + max: 18 + step: 0.5 + unit_of_measurement: "°C" + initial: 15 + icon: mdi:beach diff --git a/include/scripts/varme_styring.yaml b/include/scripts/varme_styring.yaml new file mode 100644 index 0000000..d50fd0b --- /dev/null +++ b/include/scripts/varme_styring.yaml @@ -0,0 +1,140 @@ +################################################## +# Varme: Central genberegning af alle Roth-rum +# Kaldes af automations/varme_styring.yaml ved: +# - Morgen (06:30), Nat (22:00) +# - Tilstedeværelse ændret +# - Ferietilstand ændret +# - HA genstart +# Logik pr. rum: +# - Vindue åbent → skip (håndteres af vinduer.yaml) +# - Ferie → varme_ferie_temp (frostbeskyttelse) +# - Nat (22–06:30) → komfort - varme_nat_saenkning +# - Ingen hjemme → komfort - varme_vaek_saenkning +# - Ellers → rum-komforttemperatur +################################################## + +varme_recalculate: + alias: "Varme: Genberegn alle rum" + mode: restart + sequence: + - variables: + vacation: "{{ is_state('input_boolean.vacation_mode', 'on') }}" + night: "{{ now().hour >= 22 or now().hour < 7 }}" + home: "{{ is_state('binary_sensor.family_presence', 'on') }}" + nat_sænk: "{{ states('input_number.varme_nat_saenkning') | float(3) }}" + vaek_sænk: "{{ states('input_number.varme_vaek_saenkning') | float(3) }}" + ferie_temp: "{{ states('input_number.varme_ferie_temp') | float(15) }}" + + # ---- Andreas (vindue: binary_sensor.andreas_vindue) ---- + - if: + - condition: template + value_template: "{{ not is_state('binary_sensor.andreas_vindue', 'on') }}" + then: + - service: climate.set_temperature + target: + entity_id: climate.andreas + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_andreas') | float(20) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} + + # ---- Daniel (vindue: binary_sensor.daniel_vindue) ---- + - if: + - condition: template + value_template: "{{ not is_state('binary_sensor.daniel_vindue', 'on') }}" + then: + - service: climate.set_temperature + target: + entity_id: climate.daniel + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_daniel') | float(20) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} + + # ---- Soveværelse (vindue: binary_sensor.sovevaerelse_vindue) ---- + - if: + - condition: template + value_template: "{{ not is_state('binary_sensor.sovevaerelse_vindue', 'on') }}" + then: + - service: climate.set_temperature + target: + entity_id: climate.sovev_prelse + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_sovevaerelse') | float(18) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} + + # ---- Kontor (ingen vinduesensor) ---- + - service: climate.set_temperature + target: + entity_id: climate.kontor + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_kontor') | float(21) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} + + # ---- Gang / Fordelingsgang (ingen vinduesensor) ---- + - service: climate.set_temperature + target: + entity_id: climate.fordelingsgang + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_gang') | float(18) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} + + # ---- Forgang (ingen vinduesensor) ---- + - service: climate.set_temperature + target: + entity_id: climate.forgang + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_forgang') | float(17) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} + + # ---- Lille bad (vindue: binary_sensor.lille_bad_vindue) ---- + - if: + - condition: template + value_template: "{{ not is_state('binary_sensor.lille_bad_vindue', 'on') }}" + then: + - service: climate.set_temperature + target: + entity_id: climate.lille_bad + data: + hvac_mode: heat + temperature: > + {% set k = states('input_number.varme_komfort_lille_bad') | float(22) %} + {% if vacation %} {{ ferie_temp }} + {% elif night %} {{ [k - nat_sænk, 15] | max }} + {% elif not home %} {{ [k - vaek_sænk, 15] | max }} + {% else %} {{ k }} + {% endif %} diff --git a/include/templates/varme_ventil.yaml b/include/templates/varme_ventil.yaml new file mode 100644 index 0000000..a0d9895 --- /dev/null +++ b/include/templates/varme_ventil.yaml @@ -0,0 +1,34 @@ +################################################## +# Varme: Anbefalet ventilposition (sæsonbaseret) +# Bruges til manuelt at justere: +# 1. Hoofdhanen i sauna (Roth-fordeling) +# 2. Haupthanen i bryggers (fjernvarme indgang) +# +# Formel: lineær skalering 0-100% +# Udetemperatur >= 15°C → 0% (lukket) +# Udetemperatur <= -5°C → 100% (fuldt åben) +# Lineær imellem: (15 - T) / 20 * 100 +################################################## + +- sensor: + - name: "Fjernvarme ventil anbefalet" + unique_id: fjernvarme_ventil_anbefalet + unit_of_measurement: "%" + icon: mdi:valve + state: > + {% set t = state_attr('weather.norgardsvej', 'temperature') | float(10) %} + {% set raw = (15 - t) / 20 * 100 %} + {{ [[raw, 0] | max, 100] | min | round(0) | int }} + attributes: + anbefaling: > + {% set t = state_attr('weather.norgardsvej', 'temperature') | float(10) %} + {% set raw = (15 - t) / 20 * 100 %} + {% set pos = [[raw, 0] | max, 100] | min | round(0) | int %} + {% if pos == 0 %}Lukket - varmt vejr (over 15°C) + {% elif pos <= 25 %}Let åben ca. ¼ - mildt vejr + {% elif pos <= 50 %}Halvt åben - køligt vejr + {% elif pos <= 75 %}Mest åben ca. ¾ - koldt vejr + {% else %}Fuldt åben - frostgrader + {% endif %} + udetemperatur: > + {{ state_attr('weather.norgardsvej', 'temperature') | float(10) }}