Heizungsregelung mit Schedy

Meine Heizkörper (via Fernwärme) werden seit einigen Jahren von Homematic Thermostaten vom Typ HM-CC-TC geregelt, die mit dem Stellantrieb HM-CC-VD zusammenarbeiten. Dabei handelt es sich um das erste Modell, welches für Homematic verfügbar war, leider mit einigen Kinderkrankheiten und Einschränkungen behaftet:

  • Es lässt sich nur ein Zeitprofil je Thermostat hinterlegen
  • Von der Zentrale aus lässt sich nur die Temperatur anpassen – weder der Betriebsmodus noch das Zeitprofil kann man in CCU Skripten oder auch via Home Assistant anpassen (Ausnahme: CCU Gerätekonfiguration sowie FHEM)
  • Das Einstellrädchen für die Temperatur funktioniert wenig bis gar nicht
  • Beim Wechsel von einem kleinen Öffnungsgrad zur vollständigen Schließung hat der Stellantrieb zu wenig “Wumms”, um den Stift wirklich reinzudrücken, und der Heizkörper bleibt trotz 0° Öffnung noch aktiv – bei 80°C Vorlauftemperatur (Fernwärme) reicht das, um über Nacht das Zimmer in eine gemütliche Sauna zu verwandeln…

An den Fenstern habe ich jeweils Drehgriffkontakte HM-SEC-RHS verbaut, die bislang direkt mit den Thermostaten verknüpft waren und somit autark die Temperatur bei geöffnetem Fenster abgesenkt haben. Auch die sind nicht fehlerfrei: Die Konstruktion des Batteriefachs und die Versorgung über zwei Knopfzellen sorgt regelmäßig für Wackelkontakte (Tipp: durch doppelt hohe Knopfzelle CR1/3N ersetzen!), auch die Antennenposition scheint suboptimal (http://www NULL.techwriter NULL.de/beispiel/funkeig1 NULL.htm).

FHEM war – im Gegensatz zur Homematic CCU – in der Lage, jederzeit den Betriebsmodus und sogar das Zeitprofil des Thermostats zu ändern, so dass ich via FHEM Skript einfach unterschiedliche Zeitprofile bei An- und Abwesenheit in die Thermostate geladen habe. Die eigentliche Temperaturregelung haben die Thermostate dann autark durchgeführt.

Klingt soweit gut – hat aber leider nie verlässlich funktioniert. Beim Übertragen der Zeitprofile kam es immer wieder zu Fehlern, die FHEM zwar festgestellt, aber nicht automatisch korrigiert hat, so dass ich immer mal wieder mollig geheizte Zimmer bei Abwesenheit oder auch ein kühles Bad am Morgen hatte. Nicht schön.

Beim Wechsel von FHEM auf Home Assistant stellte sich dann schnell Ernüchterung ein: Über Home Assistant ist hier nicht mehr möglich als über die CCU selbst, das bedeutet: Einstellen der aktuellen Temperatur, das war’s. Nach einigen Versuchen, mithilfe der Home Assistant Automatisierungen selbständig eine Heizungsregelung zu implementieren, bin ich dann per Zufall auf Schedy (https://hass-apps NULL.readthedocs NULL.io/en/stable/apps/schedy/) gestoßen: Einer App für den AppDaemon (lässt sich als Hass.io Add-On installieren), die beliebige Thermostate und Fensterkontakte integriert und flexibel nach Zeitprofilen ansteuert.

In Verbindung mit den HM-CC-TC gab es noch keine Klippe zu umschiffen: Deren Home Assistant-Implementierung ist fehlerhaft (https://github NULL.com/home-assistant/home-assistant/issues/30251) und signalisiert die Unterstützung sog. HVAC-Modes “off” und “heat”. In der Realität kann das Thermostat damit aber nicht umgehen – es kann nichts außer auf die vorgegebene Temperatur zwischen 6°C und 30°C heizen – und jeder Versuch, die Heizung darüber ein- oder auszuschalten, führt zu Fehlern, die Schedy dann natürlich zu Fall bringen. Glücklicherweise gibt es aber einen Workaround: Über eine Konfigurationsoption kann man Schedy dazu anweisen, die HVAC-Modes nicht zu nutzen, und schon funktioniert alles wie gewünscht. Der Beginn der Schedy Konfigurationsdatei (schedy_heating.yaml) sieht daher wie folgt aus:

schedy_heating:
  module: hass_apps_loader
  class: SchedyApp

  actor_type: thermostat
  actor_templates:
    default:
      off_temp: 6
      supports_hvac_modes: false

Als nächstes musste ich mir überlegen, welche Heizprofile es geben sollte, Schedy ist da völlig flexibel konfigurierbar. Ich habe mich zunächst auf die folgenden vier festgelegt:

  • anwesend/zeitgesteuert: Je nach Raum und Zeit wird auf eine angenehme Temperatur geheizt
  • abwesend/zeitgesteuert: Tagsüber wird ein wenig mehr geheizt als nachts, aber dies dient nur dem Schutz gegen Schimmel und gegen Auskühlen
  • durchgehend aktiv: Je nach Raum wird auf eine angenehme Temperatur geheizt, unabhängig von der Uhrzeit (Partymodus)
  • aus: Es wird nicht geheizt bzw. die minimal mögliche Temperatur eingestellt, in diesem Fall 6°C.

Zur Auswahl dient eine input_select Integration in der configuration.yaml:

 input_select:
  heating_mode:
    name: Heizungsmodus
    options:
    - anwesend/zeitgesteuert
    - abwesend/zeitgesteuert
    - durchgehend aktiv
    - aus
    icon: mdi:home-thermometer-outline 

Ob man den Heizungsmodus nun über das Lovelace-Webinterface, eine automatische Anwesenheitserkennung oder über einen Taster umschaltet, bleibt natürlich jedem selbst überlassen. In meinem Falle habe ich mich für die ersten zwei genannten Varianten entschieden.

Der Heizungsmodus wird nun über die Funktion heating_mode() in der schedy_heating.yaml übergeben:

  expression_environment: |
    def heating_mode():
        return state("input_select.heating_mode")

Anschließend folgt die Definition der Zeitprofile, die später den Heizungsmodi und den Räumen zugeteilt werden:

  schedule_snippets:

    ss_aus: 
    - value: 6

    ss_durchgehend_wohnen:
    - value: 22

    ss_durchgehend_sonstige:
    - value: 18.5

    ss_abwesend:
    - value: 18.5
      start: "10:00"
      end: "20:00"
  
    ss_wohnen:
    - value: 22
      rules:
      - weekdays: 1-4,7
        start: "10:00"
        end: "21:30"
      - weekdays: 5,6
        start: "10:00"
        end: "22:00"

    ss_bad:
    - value: 22
      rules:
      - weekdays: 1-5
        start: "5:45"
        end: "10:00"
      - weekdays: 6
        start: "8:00"
        end: "10:00"
      - weekdays: 7
        start: "8:00"
        end: "10:00"
    - value: 18.5
      rules:
      - weekdays: 1-5
        start: "10:00"
        end: "21:30"
      - weekdays: 6
        start: "10:00"
        end: "22:00"
      - weekdays: 7
        start: "10:00"
        end: "21:30"

    ss_sonstige:
    - value: 18.5
      start: "10:00"
      end: "20:00"

Schließlich wird definiert, bei Änderungen welcher Entity Schedy den Zeitplan neu evaluieren soll. In unserem Fall ist das besagte input_select Integration:

  watched_entities:
  - input_select.heating_mode

Nun kommen Regeln, die dem Zeitplan jedes Raumes vorangestellt und angehangen werden sollen. Über diese Regeln wird genauso die Temperaturabsenkung bei offenem Fenster realisiert wie die Aktivierung von Heizungsmodi, die für alle Räume gleich gelten. Für die Details sei hier auf die wirklich sehr gute und ausführliche Schedy-Dokumentation (https://hass-apps NULL.readthedocs NULL.io/en/stable/apps/schedy/) verwiesen.

Neben den besagten Drehgriffkontakten HM-SEC-RHS (liefern open/tilted/closed als State) kommt an meiner Wohnungstür auch ein HM-SEC-SCo (liefert on/off) zum Einsatz. Die Temperaturabsenkung im schedule_prepend Block wurde so gestaltet, dass sie mit beiden Varianten umgehen kann.

  schedule_prepend:
  - x: "Mark(OFF, Mark.OVERLAY) if not (is_empty(filter_entities('sensor', state='open', window_room=room_name))) else Next()"
  - x: "Mark(OFF, Mark.OVERLAY) if not (is_empty(filter_entities('sensor', state='tilted', window_room=room_name))) else Next()"
  - x: "Mark(OFF, Mark.OVERLAY) if not (is_empty(filter_entities('binary_sensor', state='on', window_room=room_name))) else Next()"
  - x: "IncludeSchedule(schedule_snippets['ss_abwesend']) if heating_mode() == 'abwesend/zeitgesteuert' else Next()"
  - x: "IncludeSchedule(schedule_snippets['ss_aus']) if heating_mode() == 'aus' else Next()"

  schedule_append:
  - value: "17"

Schließlich bleibt noch die Zuordnung der Räume zu den Fenstergriffsensoren und den Zeitprofilen:

  rooms:
    sz:
      actors:
        climate.sz_ht_heizung:
      watched_entities:
      - sensor.sz_fg_fenster_state
      schedule:
      - x: "IncludeSchedule(schedule_snippets['ss_sonstige']) if heating_mode() == 'anwesend/zeitgesteuert' else Next()"
      - x: "IncludeSchedule(schedule_snippets['ss_durchgehend_sonstige']) if heating_mode() == 'durchgehend aktiv' else Next()"
    az:
      actors:
        climate.az_ht_heizung:
      watched_entities:
      - sensor.az_fg_fenster_state
      schedule:
      - x: "IncludeSchedule(schedule_snippets['ss_wohnen']) if heating_mode() == 'anwesend/zeitgesteuert' else Next()"
      - x: "IncludeSchedule(schedule_snippets['ss_durchgehend_wohnen']) if heating_mode() == 'durchgehend aktiv' else Next()"
    bz:
      actors:
        climate.bz_ht_heizung:
      watched_entities:
      - sensor.bz_fg_fenster_state
      schedule:
      - x: "IncludeSchedule(schedule_snippets['ss_bad']) if heating_mode() == 'anwesend/zeitgesteuert' else Next()"
      - x: "IncludeSchedule(schedule_snippets['ss_durchgehend_sonstige']) if heating_mode() == 'durchgehend aktiv' else Next()"
    ku:
      actors:
        climate.ku_ht_heizung:
      watched_entities:
      - sensor.ku_fg_fenster_state
      schedule:
      - x: "IncludeSchedule(schedule_snippets['ss_sonstige']) if heating_mode() == 'anwesend/zeitgesteuert' else Next()"
      - x: "IncludeSchedule(schedule_snippets['ss_durchgehend_sonstige']) if heating_mode() == 'durchgehend aktiv' else Next()"
    wz:
      actors:
        climate.wz_ht_heizung:
      watched_entities:
      - sensor.wz_fg_fenster_state
      - sensor.wz_fg_tuer_state
      schedule:
      - x: "IncludeSchedule(schedule_snippets['ss_wohnen']) if heating_mode() == 'anwesend/zeitgesteuert' else Next()"
      - x: "IncludeSchedule(schedule_snippets['ss_durchgehend_wohnen']) if heating_mode() == 'durchgehend aktiv' else Next()"
    wf:
      actors:
        climate.wf_ht_heizung:
      watched_entities:
      - binary_sensor.wf_tk_wohnungstuer_state
      schedule:
      - x: "IncludeSchedule(schedule_snippets['ss_sonstige']) if heating_mode() == 'anwesend/zeitgesteuert' else Next()"
      - x: "IncludeSchedule(schedule_snippets['ss_durchgehend_sonstige']) if heating_mode() == 'durchgehend aktiv' else Next()"

Schließlich ist es noch notwendig, in der customize.yaml die Tür-/Fensterkontakte den einzelnen Räumen zuzuordnen:

sensor.sz_fg_fenster_state:
  friendly_name: Sz Fenster
  window_room: sz
sensor.az_fg_fenster_state:
  friendly_name: Az Fenster
  window_room: az
sensor.bz_fg_fenster_state:
  friendly_name: Bz Fenster
  window_room: bz
sensor.ku_fg_fenster_state:
  friendly_name: Kü Fenster
  window_room: ku
sensor.wz_fg_tuer_state:
  friendly_name: Wz Tür
  window_room: wz
sensor.wz_fg_fenster_state:
  friendly_name: Wz Fenster
  window_room: wz
binary_sensor.wf_tk_wohnungstuer_state:
  friendly_name: Wf Tür
  icon: mdi:door
  window_room: wf

Damit ist die Implementierung vollständig.

Natürlich empfiehlt es sich nicht, direkt mit der vollständigen Konfiguration zu beginnen – lieber erst mit einem Raum, einem Zeitprofil und ohne Fensterkontakte starten und dann die Funktionalität schrittweise erweitern. Ein paar Tage Zeit sollte man dafür schon einplanen, trivial ist das ganze nicht unbedingt – aber es macht Spaß! 😉

Nach Änderungen an der schedy_heating.yaml werden die Änderungen automatisch neu eingelesen. Fehlermeldungen tauchen im Log des AppDaemon (unter Hass.io -> AppDaemon ganz nach unten scrollen und ggf. nochmal REFRESH drücken) auf und sind in der Regel relativ aussagekräftig. Ansonsten findet man im Support-Thread in der Home Assistant Community (https://community NULL.home-assistant NULL.io/t/heaty-will-die-schedy-be-born/71276) meist schnell Hilfe.

Ergänzung vom 2020-02-02: Die HM-CC-TC müssen im Modus “Manu” laufen, nicht im Modus “Cent” oder “Auto”:

  • Im Modus “Cent” werden manuelle Änderungen am Thermostat binnen Minuten wieder überschrieben. Die Zentrale gewinnt hier immer.
  • Im Modus “Auto” steuert der lokale Zeitplan im Thermostat. Den wollen wir aber ja gerade mit Schedy ablösen.
  • Im Modus “Manu” funktioniert alles wie gewünscht: Manuelle Änderungen am Thermostat sind möglich, werden aber zu den Umschaltpunkten durch Schedy wieder überschrieben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.