Im vorherigen Part habe ich die Lichtszenen und deren Aktivierung beschrieben. Diesmal möchte ich tiefer in das Konzept des Trigger-basierten Template Sensors eintauchen und zeigen, wie dieser verwendet werden kann, um komplexere Szenarien in Home Assistant zu handhaben.
Stand der Dinge#
Rufen wir uns doch noch einmal eine verkürzte Version meines Sensors in Erinnerung:
- trigger:
- platform: homeassistant
event: start
- platform: event
event_type: call_service
event_data:
domain: scene
service: turn_on
action:
- variables:
history: >
{{ ... }}
sensor:
- name: scene_history_wohnzimmer
unique_id: sensor_scene_history_wohnzimmer
state: >
{{ state_attr(history.wohnzimmer[0], "name") }}
attributes:
current: "{{ history.wohnzimmer[0] }}"
history: "{{ history.wohnzimmer[1:] }}"
# ... weitere Räume einfügen
Bei jedem Start von Home Assistant sowie jeder Aktivierung einer Szene wird die Aktualisierung des Trigger-basierten Template Sensors ausgelöst. Zuerst werden die Actions abgearbeitet, die in meinem Fall die Variable history
mit Daten für alle Räume füllt. Danach werden die Sensor-Konfigurationen nacheinander ausgeführt.
Während also der scene_history_wohnzimmer
Sensor aktualisiert wird, steht die history
Variable bereits mit allen Werten für das Wohnzimmer zur Verfügung. Diese Tatsache müssen wir im Kopf behalten, wenn wir solche Sensoren bauen. Das gilt natürlich auch für die Sensoren aller weiteren Räume, die wir an unseren Trigger anheften.
Und hier liegt ein kleines Detail versteckt: sobald die history
Variable nach Auslösen des Triggers für alle Räume befüllt wird, kann sie nämlich die Sensordaten aller Räume aktualisieren - quasi in einem Durchlauf. Ja, so werden auch die Sensoren der Räume aktualisiert, in denen gerade keine Szene aktiviert wurde. Das werden wir aber später noch brauchen 😁.
Herausforderung#
Wir haben es im ersten Part erfolgreich geschafft, dass der Name der zuletzt aktivierten Szene im Scene-History-Sensor gespeichert wird. Konkret stand der Sensor auf Essen
und verhinderte somit, dass während dem Essen die Wohnzimmer-Beleuchtung gedimmt wird, wenn jemand den Fernseher einschaltet.
Doch was passiert nun, wenn das Licht zwischenzeitlich ausgeschaltet wird? Du ahnst es vermutlich schon: nichts. Die letzte Szene Essen
wird solange beibehalten, bis eine andere Szene im Wohnzimmer aktiviert wird. Und hier endet die Geschichte auch schon. Dies wird in anderen Situationen dafür sorgen, dass Automatisierungen eine Szene vermuten und entsprechend reagieren, obwohl sie mittlerweile gar nicht mehr aktiv sein könnte.
Um dieses Problem zu lösen, erweitern wir nun unseren Scene-History-Sensor um weitere Trigger und Attribute.
Erweiterung des Sensors#
Wir fügen einen weiteren Trigger, ein neues Attribut und ein Makro1 hinzu.
Trigger#
Ich teile den Triggern nun auch Trigger-IDs zu, um innerhalb des Trigger-basierten Template Sensors prüfen zu können, durch welches Ereignis er eigentlich aktualisiert wird. Entitäten wie light.wohnzimmer_lights
gibt es bei mir für jeden Raum, sie gruppieren sämtliche Lampen innerhalb eines Raumes. Das ermöglicht mir die extrem bequeme Abfrage des Beleuchtungsstatus, oder eben alle Lichter gleichzeitig auszuschalten.
- trigger:
- platform: homeassistant
event: start
- platform: event
event_type: call_service
event_data:
domain: scene
service: turn_on
id: scene_activated # das ist neu
# und ein neuer Trigger
- platform: state
entity_id:
- light.wohnzimmer_lights
from: "on"
to: "off"
id: off_again
# ...
Attribut#
Statten wir den Scene-History-Sensor im Wohnzimmer nun mit dem Attribut aus, welches in Zukunft die Information vorhält, ob das Licht nach dem Aktivieren einer Szene wieder ausgeschaltet wurde.
# ...
- name: scene_history_wohnzimmer
unique_id: sensor_scene_history_wohnzimmer
state: >
{{ state_attr(history.wohnzimmer[0], "name") }}
attributes:
current: "{{ history.wohnzimmer[0] }}"
history: "{{ history.wohnzimmer[1:] }}"
# das kommt dazu
off_again: >
{% from "scenes.jinja" import get_off_again %}
{{ get_off_again("wohnzimmer", trigger) }}
Ich habe mich für den Namen off_again
entschieden. Das Template des Attributs importiert ein Makro und führt es dann aus. Damit ich das Template der Funktion get_off_again
auch für andere Räume benutzen kann, ohne es immer wieder kopieren zu müssen, habe ich es in eben jenem Makro ausgelagert. Das ist übrigens der übliche Use-Case für Makros, falls du dich schon mal gefragt hast, wozu die eigentlich gut sein sollen 😁.
An das Makro übergebe ich den gewünschten Raum und das gesamte trigger
Objekt, welches von Home Assistant zur Verfügung gestellt wird. In diesem Objekt enthalten ist auch die Information, welcher Trigger ausgelöst wurde.
Makro#
Um eigene Makros zu verwenden, erstelle im config
-Ordner deiner Home Assistant Installation den Unterordner custom_templates
. Hier legst du deine .jinja-Dateien ab. Ich habe mich für den Dateinamen scenes.jinja
entschieden, einfach weil ich es vorteilhaft finde, Informationen thematisch zu strukturieren.
Die Datei hat folgenden Inhalt:
{% macro get_off_again(area, trigger) %}
{# eine Szene wurde aktiviert #}
{% if trigger.id == "scene_activated" %}
{% set areas = trigger.event.data.service_data.entity_id
| map("area_id")
| list %}
{% if area in areas %}
{% set return = "no" %}
{% endif %}
{# Lampen wurden ausgeschaltet #}
{% elif trigger.id == "off_again" %}
{% set areas = [area_id(trigger.entity_id)] %}
{% if area in areas %}
{% set return = "yes" %}
{% endif %}
{% endif %}
{# Nichts von beidem #}
{% if return is not defined %}
{% set return = state_attr("sensor.scene_history_" + area, "off_again") %}
{% endif %}
{{ return }}
{% endmacro %}
Erläuterungen#
Das Makro wird mit zwei Parametern aufgerufen. Dies ist einerseits area
, die in meinem Beispiel ja auf wohnzimmer
gesetzt ist. Andererseits das trigger
Objekt von Home Assistant.
Wird eine Szene aktiviert, soll überprüft werden, ob die ausgelöste Szene im wohnzimmer
ist. Falls ja, wird off_again
auf no gesetzt. Dieselbe Logik wende ich an, wenn Lampen ausgeschaltet werden. Es wird überprüft, ob es sich um den gewünschten Raum handelt und falls ja, off_again
auf yes gesetzt. Du hast richtig gemerkt: wir haben einen Schalter im klassischen Sinne gebaut, der entweder an oder aus ist. Macht bis hierher Sinn, oder?
Für den Fall, dass weder die aktivierte Szene, noch die ausgeschaltete Lampe aus dem wohnzimmer
sind, wird einfach der aktuell eingestellte Wert übernommen. Warum das notwendig ist? Ich habe dir weiter oben einen brennenden Tipp dazu gegeben 😎.
Im letzten Schritt wird der Wert der Variable return
nun zurückgegeben und in der Folge als off_again
Attribut festgelegt.
Abschlussarbeiten#
Der Scene-History-Sensor kann nun nicht nur erfolgreich die zuletzt aktivierte Szene anzeigen, sondern stellt darüber hinaus auch ein Attribut bereit mit der Information, ob das Licht seit Aktivierung einer Szene wieder abgeschaltet wurde. Damit kann die in Part 1 aufgebaute Automatisierung nicht nur feststellen, ob die Szene Essen
im Wohnzimmer zuletzt aktiviert wurde, sondern auch, ob das Licht seither wieder ausgeschaltet worden ist.
Sobald der Fernseher im Wohnzimmer eingeschaltet wird, überprüft die für das Dimmen verantwortliche Automatisierung in Zukunft nicht nur, ob der Scene-History-Sensor auf Essen
steht, sondern auch, ob das Licht seither wieder abgeschaltet wurde.
- condition: not
conditions:
- condition: state
entity_id: sensor.scene_history_wohnzimmer
state: Essen
- condition: state
entity_id: sensor.scene_history_wohnzimmer
attribute: off_again
state: "yes"
Jetzt wird die Automatisierung wirklich zuverlässig laufen und das Licht nur im vorgesehenen Moment dimmen 😁. Wenn du bessere Ideen zu einer möglichen Umsetzung hast, schreib mir gern. Mein Ziel war die Vermeidung der Erstellung von unzähligen Helfern.
Im nächsten Beitrag zu Home Assistant werde ich darüber berichten, wie ich mit Hilfe der Local calendar, To-do list und Roborock Integrations einen interaktiven Reinigungsplan erstellt habe.
Feature-Foto von Bilal Mansuri auf Unsplash
Seit der Version 2023.4 unterstützt Home Assistant die Erstellung und Wiederverwendung eigener Makros, siehe hier. ↩︎