all systems self-hosted

~/selfhostjournal $

← Alle Artikel

Heizungsautomationen in Home Assistant: Logik pro Raum, TRV-Kalibrierung und unsere Probleme

6–10 Minuten

Kurz gesagt

Problem: Heizkörperthermostate messen die Temperatur direkt neben dem heißen Heizkörper, ein gemeinsamer Blueprint reagierte nicht mehr, und ein Update hat die Heizung unbemerkt lahmgelegt.

Lösung: Drei kleine Automationen pro Raum (Toggle, Target Sync, Calibration), ein echter Raumsensor als Messwert für jedes Ventil und ein paar Sicherheitsnetze, die melden, wenn etwas aus dem Ruder läuft.

Getestet mit: Home Assistant, Zigbee2MQTT 2.14, 12 Heizkörperventile SONOFF TRVZB, Zigbee-Temperatur- und Bewegungssensoren

Unser Haus hat neun beheizte Räume mit zwölf smarten Heizkörperventilen. Das Ziel war einfach: warm, wenn jemand im Raum ist, ein paar Grad weniger, wenn nicht, und keine Heizung bei offenem Fenster. Bis dahin hat es ein paar Umbauten gebraucht. Hier ist das Setup, das jetzt funktioniert, und die Probleme, auf die wir unterwegs gestoßen sind.

Die Bausteine pro Raum

Jeder Raum nutzt dieselben Helfer. Dadurch sind die Automationen fast identisch, und ein neuer Raum ist im Wesentlichen kopieren und umbenennen.

HelferZweck
input_boolean.heating_office_onHauptschalter für den Raum (Dashboard, Telegram, Skripte „alle an/aus“)
input_number.temperature_comfort_officeKomforttemperatur, zum Beispiel 21 °C
input_number.temperature_eco_officeECO-Temperatur, zum Beispiel 19 °C
schedule.schedule_heating_officeWann der Raum überhaupt geheizt werden soll

Dazu hat jeder Raum drei Automationen:

  • Toggle folgt dem Hauptschalter und schaltet Ventil und Target Sync ein oder aus.
  • Target Sync entscheidet zwischen Komfort und ECO und schreibt die Zieltemperatur ans Ventil.
  • Calibration gibt die echte Raumtemperatur an das Ventil weiter.

Warum ich den Blueprint ersetzt habe

Am Anfang liefen alle Räume über einen gemeinsamen Heizungs-Blueprint. Das war bequem, bis es das nicht mehr war: Ende August reagierte er auf einige Eingaben einfach nicht mehr, weil eine interne Schutzbedingung fehlschlug. Ein Fehler in einem gemeinsamen Blueprint trifft alle Räume gleichzeitig, und die Logik lässt sich von außen schlecht untersuchen.

Ich habe ihn durch drei einfache Automationen pro Raum ersetzt. Das sind mehr Automationen (33 für das ganze Haus), aber jede ist kurz, macht genau eine Sache und ist im Trace gut zu verfolgen, wenn etwas schiefgeht.

1. Toggle

Geht der Hauptschalter an, wird das Ventil auf heat gesetzt, der Target Sync eingeschaltet und einmal ausgeführt, damit sofort die richtige Temperatur gilt. Geht er aus, wird zuerst der Target Sync abgeschaltet und dann das Ventil ausgeschaltet.

alias: Office - Heating - Toggle
triggers:
  - trigger: state
    entity_id: input_boolean.heating_office_on
    to: "on"
    id: turned_on
  - trigger: state
    entity_id: input_boolean.heating_office_on
    to: "off"
    id: turned_off
actions:
  - choose:
      - conditions:
          - condition: trigger
            id: turned_on
        sequence:
          - action: climate.set_hvac_mode
            target:
              entity_id: climate.office_heating_valve
            data:
              hvac_mode: heat
          - action: automation.turn_on
            target:
              entity_id: automation.office_heating_target_sync
          - action: automation.trigger
            target:
              entity_id: automation.office_heating_target_sync
      - conditions:
          - condition: trigger
            id: turned_off
        sequence:
          - action: automation.turn_off
            target:
              entity_id: automation.office_heating_target_sync
          - action: climate.set_hvac_mode
            target:
              entity_id: climate.office_heating_valve
            data:
              hvac_mode: "off"
mode: single

2. Target Sync

Beim Target Sync unterscheiden sich die Räume. Im Büro folgt er einem Bewegungsmelder: Komfort nach zwei Minuten Bewegung, ECO nach zehn Minuten ohne. Die Verzögerungen verhindern, dass die Heizung hoch- und runterspringt, wenn jemand nur kurz durchläuft.

alias: Office - Heating - Target Sync
triggers:
  - trigger: state
    entity_id: binary_sensor.office_motion
    to: "on"
    for: { minutes: 2 }
  - trigger: state
    entity_id: binary_sensor.office_motion
    to: "off"
    for: { minutes: 10 }
  - trigger: state
    entity_id:
      - input_number.temperature_comfort_office
      - input_number.temperature_eco_office
  - trigger: state
    entity_id: input_boolean.heating_office_on
    to: "on"
conditions:
  - condition: state
    entity_id: input_boolean.heating_office_on
    state: "on"
actions:
  - if:
      - condition: state
        entity_id: binary_sensor.office_motion
        state: "on"
    then:
      - action: climate.set_temperature
        target:
          entity_id: climate.office_heating_valve
        data:
          temperature: "{{ states('input_number.temperature_comfort_office') | float }}"
    else:
      - action: climate.set_temperature
        target:
          entity_id: climate.office_heating_valve
        data:
          temperature: "{{ states('input_number.temperature_eco_office') | float }}"
mode: restart

Andere Räume nutzen andere Signale nach demselben Muster:

  • Nur Zeitplan (Küche, Schlafzimmer, Bad): Komfort innerhalb des Zeitplans, ECO außerhalb.
  • Zeitplan und Anwesenheit (Räume, die einer Person gehören): Komfort nur, wenn der Zeitplan aktiv ist und diese Person zu Hause ist.
  • Ein Gerät als Anwesenheit: Im Gaming-Raum ist der AV-Receiver das beste Zeichen, dass jemand da ist. Receiver an heißt Komfort, Receiver aus heißt abgesenkte Temperatur.

3. Calibration: der wichtigste Teil

Ein Heizkörperthermostat misst die Temperatur dort, wo es sitzt: direkt neben dem heißen Heizkörper. Es hält den Raum also für warm, lange bevor er es ist, und schließt zu früh.

Das SONOFF TRVZB kann stattdessen eine externe Temperatur verwenden. In Zigbee2MQTT gibt es dafür zwei Entitäten:

  • ein Select „Temperature sensor“: local_temperature (der eigene Sensor) oder remote_temperature (ein externer Wert)
  • eine Number „External temperature input“, die den externen Wert empfängt

Die Calibration-Automation kopiert den Wert eines echten Raumsensors in diesen Eingang, sobald die Messung zwei Minuten stabil ist. Außerdem prüft sie das Select, denn nach einem Neuverbinden oder Batteriewechsel fällt das Ventil manchmal auf seinen eigenen Sensor zurück.

alias: Office - Climate - Calibration
triggers:
  - trigger: state
    entity_id: sensor.office_temperature
    for: { minutes: 2 }
  - trigger: state
    entity_id: select.office_heating_valve_temperature_sensor_select
    not_to:
      - remote_temperature
      - remote_source_offline
      - unavailable
      - unknown
conditions:
  - condition: numeric_state
    entity_id: sensor.office_temperature
    above: 0
actions:
  # das Ventil wieder auf den externen Sensor stellen, falls es zurückgefallen ist
  - if:
      - condition: not
        conditions:
          - condition: state
            entity_id: select.office_heating_valve_temperature_sensor_select
            state:
              - remote_temperature
              - remote_source_offline
    then:
      - action: select.select_option
        target:
          entity_id: select.office_heating_valve_temperature_sensor_select
        data:
          option: remote_temperature
        continue_on_error: true
  # die echte Raumtemperatur an das Ventil geben
  - action: number.set_value
    target:
      entity_id: number.office_heating_valve_external_temperature_input
    data:
      value: "{{ states('sensor.office_temperature') | float }}"
mode: single

Tipp: Lass remote_source_offline in Ruhe. Das ist die eigene Rückfallebene des Ventils, wenn der externe Wert veraltet ist. Erzwingst du dann wieder remote_temperature, heizt das Ventil mit einem alten Wert.

Die Bedingung above: 0 verhindert, dass ein Sensor, der 0 oder gar nichts meldet, das Haus herunterkühlt. Mit der Calibration erreicht der Raum endlich die Temperatur, die das Dashboard anzeigt.

4. Keine Heizung bei offener Tür

Das Wohnzimmer hat eine Terrassentür und zwei Fenster, und die Heizung lief weiter, wenn sie offen waren. Die Pause-Automation schaltet die drei Ventile aus, wenn eine Tür oder ein Fenster eine Minute offen ist, und schaltet sie wieder ein, wenn alle wieder geschlossen sind.

Das wichtige Detail: Sie fasst den Hauptschalter nicht an. Stattdessen setzt sie ein eigenes Flag (input_boolean.heating_living_room_paused). Toggle und Target Sync lassen die Ventile in Ruhe, solange das Flag an ist. Weil das Flag ein Helfer ist und kein Warten innerhalb der Automation, übersteht es auch einen Neustart von Home Assistant. Ein Start-Trigger stellt die Heizung wieder her, falls alles geschlossen wurde, während Home Assistant nicht lief.

triggers:
  - trigger: state
    entity_id: [binary_sensor.terrace_door, binary_sensor.living_room_window_1, binary_sensor.living_room_window_2]
    to: "on"
    for: { minutes: 1 }
    id: opened
  - trigger: state
    entity_id: [binary_sensor.terrace_door, binary_sensor.living_room_window_1, binary_sensor.living_room_window_2]
    from: "on"
    to: "off"
    id: closed
  - trigger: homeassistant
    event: start
    id: ha_start
actions:
  - choose:
      - conditions:   # geöffnet, während die Heizung an ist -> pausieren
          - condition: trigger
            id: opened
          - condition: state
            entity_id: input_boolean.heating_living_room_on
            state: "on"
        sequence:
          - action: input_boolean.turn_on
            target: { entity_id: input_boolean.heating_living_room_paused }
          - action: climate.set_hvac_mode
            target: { entity_id: [climate.living_room_heating_1, climate.living_room_heating_2, climate.living_room_heating_3] }
            data: { hvac_mode: "off" }
      - conditions:   # alles zu und von uns pausiert -> fortsetzen
          - condition: trigger
            id: [closed, ha_start]
          - condition: state
            entity_id: [binary_sensor.terrace_door, binary_sensor.living_room_window_1, binary_sensor.living_room_window_2]
            state: "off"
          - condition: state
            entity_id: input_boolean.heating_living_room_paused
            state: "on"
        sequence:
          - action: input_boolean.turn_off
            target: { entity_id: input_boolean.heating_living_room_paused }
          - if:
              - condition: state
                entity_id: input_boolean.heating_living_room_on
                state: "on"
            then:
              - action: climate.set_hvac_mode
                target: { entity_id: [climate.living_room_heating_1, climate.living_room_heating_2, climate.living_room_heating_3] }
                data: { hvac_mode: heat }
              - action: automation.trigger
                target: { entity_id: automation.living_room_heating_target_sync }
mode: queued

5. Sicherheitsnetze

Automationen scheitern leise. Diese drei sorgen dafür, dass ich es mitbekomme:

  • Kindersicherung erzwingen: Nach einem Batteriewechsel oder Neu-Anlernen kann die Kindersicherung eines Ventils aus sein, und dann kann jeder am Rädchen drehen. Ist eine der zwölf Sperren 10 Sekunden lang aus, oder startet Home Assistant, werden alle Sperren wieder eingeschaltet.
  • Warnung bei falscher Zieltemperatur: 10 Minuten nachdem sich die Zieltemperatur eines Ventils oder ein Komfort-/ECO-Wert geändert hat, prüft ein Template jedes Ventil. Passt eine Zieltemperatur weder zum ECO- noch zum Komfortwert ihres Raums (Toleranz 0,25 °C), bekomme ich eine Telegram-Nachricht. Räume mit ausgeschalteter Heizung, ausgeschaltete Ventile und das pausierte Wohnzimmer werden übersprungen. So fällt ein Target Sync auf, der das Ventil nicht erreicht hat.
  • Warnung bei neuer Zigbee2MQTT-Version: eine Nachricht, sobald Zigbee2MQTT in einer neuen Version läuft. Den Grund liest du im nächsten Abschnitt.

Der Kern der Prüfung, vereinfacht auf ein Ventil:

{% set target  = state_attr('climate.office_heating_valve', 'temperature') | float %}
{% set eco     = states('input_number.temperature_eco_office') | float %}
{% set comfort = states('input_number.temperature_comfort_office') | float %}
{{ (target - eco) | abs > 0.25 and (target - comfort) | abs > 0.25 }}

Die Probleme, die wir hatten

ProblemUrsacheLösung
Räume reagierten nicht auf Zeitplan- oder BewegungsänderungenDie interne Schutzbedingung des gemeinsamen Heizungs-Blueprints schlug fehlDrei eigene Automationen pro Raum statt des Blueprints
Räume blieben kälter als die ZieltemperaturDas Ventil maß direkt neben dem HeizkörperCalibration mit einem echten Raumsensor
Ventil fiel auf den eigenen Sensor zurückNeuverbinden oder Batteriewechsel setzt das Select zurückCalibration reagiert auch auf das Select und stellt es zurück
Heizung lief bei offener TerrassentürKeine Pause-LogikTür- und Fensterpause mit eigenem Flag
Calibration funktionierte unbemerkt nicht mehrEin automatisches Update von Zigbee2MQTT 2.14.1 auf 2.14.2 hat die Sensor-Optionen des TRVZB umbenanntAutomationen auf die neuen Optionsnamen umgestellt, dazu eine Warnung bei Versionswechsel
Ventile ließen sich von Hand verstellenKindersicherung nach Batteriewechsel oder Neu-Anlernen ausKindersicherung wird erzwungen
Ein Ventil stand unbemerkt auf einer falschen TemperaturEin Target Sync, der das Ventil nicht erreicht hatWarnung bei falscher Zieltemperatur

Achtung: Läuft Zigbee2MQTT mit dem Image latest und aktualisiert sich selbst, kann eine Änderung im Konverter über Nacht Entitäten oder Optionen umbenennen. Es gibt keinen Fehler, die Heizung tut einfach still und leise nicht mehr, was du denkst. Entweder die Version festlegen und bewusst aktualisieren, oder dich zumindest bei einem Versionswechsel benachrichtigen lassen.

Was ich gelernt habe

  • Kleine, langweilige Automationen pro Raum schlagen einen cleveren gemeinsamen Blueprint. Sie sind leichter zu lesen, zu testen und zu reparieren.
  • Ein Heizkörperthermostat ohne externen Sensor heizt auf die falsche Temperatur. Ihm einen echten Raumsensor zu geben, ist die zusätzliche Automation wert.
  • Nutze ein Flag als Helfer statt eines Wartens für alles, was einen Neustart überstehen muss.
  • Jede Automation, die still scheitern kann, braucht eine Warnung, die das Ergebnis prüft, nicht nur den Auslöser.

Alles hier hat bei mir zum Zeitpunkt des Schreibens funktioniert. Software ändert sich, und dein Setup ist anders: mach vorher ein Backup, teste vorsichtig und wende die Schritte auf eigenes Risiko an. Details im Impressum.