eval und eval_trigger
Attribut eval
Wenn ein Item einen neuen Wert zugewiesen bekommen soll (z.B. via KNX oder Logik), wird der neue Wert zunächst in value zwischengespeichert. Wenn ein Attribut eval existiert, so wird der Ausdruck hinter eval = … ausgeführt und das Ergebnis dieses Ausdrucks als neuer Wert ins Item übernommen. Sollten alter und neuer Wert des Items unterschiedlich sein oder ist das Attribut enforce_updates vorhanden und auf True gesetzt, dann werden abhängige Logiken getriggert.
Im folgenden Beispiel liefert ein Sensor die Temperatur in Fahrenheit. Das Item soll aber die Temperatur in °Celsius speichern.
Temperatur:
# Formel (°F - 32) x 5/9 = °C
type: num
eval: (value - 32 ) * 5 / 9 # Aus 68°F werden somit 20°C
- Die Auswertung des eval Ausdrucks wird gestartet, wenn:
dem Item ein neuer Wert zugewiesen wird (siehe Erläuterug im ersten Absatz)
sich der Wert des oder der Items aus dem eval_trigger ändert (siehe Erläuterug weiter unten)
ein timer verwendet wird und die angegebene Zeit abgelaufen ist
ein autotimer verwendet wird und die angegebene Zeit abgelaufen ist
ein crontab definiert ist und die zeitlichen Angaben zutreffen
Wenn das Attribut eval_on_trigger_only gesetzt ist, wird der eval Ausdruck nur ausgewertet, wenn ein eval_trigger der Auslöser war; in allen anderen Fällen (Zuweisung durch Plugin, Logik, Konsole, AdminUI o.ä.) wird der Wert gesetzt wie bei einem normalen Item ohne eval Ausdruck.
Das Eval Attribut kann auch bis zu einem gewissen Grad Logiken beinhalten. Wichtig ist, dass bei der Angabe eines if auch ein else implementiert sein muss. Außerdem ist dem Item ein sh. voran zu setzen. Die () Klammern hinter dem Item sind nötig, um den Item-Wert abzufragen. Anstelle der Klammern kann auch property.value genutzt werden.
Temperatur:
Trigger:
# Wird wahr, wenn die Temperatur über 20 Grad wird und falsch, wenn nicht.
type: bool
eval: 1 if sh.Temperatur() > 20 else 0
# alternativ eval: 1 if sh.Temperatur.property.value > 20 else 0
eval_trigger: Temperatur
Weiter ist es möglich, direkt die Werte der eval_trigger im eval entsprechend auszuwerten:
Keyword |
Beschreibung |
---|---|
sum |
Errechnet die Summe aller eval_trigger Items. |
avg |
Errechnet den Mittelwert aller Items auf die sich eval_trigger bezieht. |
min |
Errechnet den Minimalwert aller Items auf die sich eval_trigger bezieht. |
max |
Errechnet den Maximalwert aller Items auf die sich eval_trigger bezieht. |
and |
Setzt den Wert des Items auf True, wenn alle Items auf die sich eval_triggers bezieht den Wert True haben. |
or |
Setzt den Wert des Items auf True, wenn eines der Items auf die sich eval_triggers bezieht den Wert True haben. |
Beispiel:
Raum:
Temperatur:
type: num
name: average temperature
eval: avg
eval_trigger:
- room_a.temp
- room_b.temp
Praesenz:
type: bool
name: movement in on the rooms
eval: or
eval_trigger:
- room_a.presence
- room_b.presence
zusätzliche Funktionen in eval Ausdrücken
Bereits SmartHomeNG v1.3 wird das Python Modul math bereitgestellt und es können entsprechende Funktionen genutzt werden. Außerdem sind seit SmarthomeNG v1.7 die Items-API als items (z.B. items.return_item(‚bla‘)) und das shtime Modul mittels shtime (z.B. shtime.now()) verfügbar.
Beispiel:
oneitem:
type: num
eval: math.ceil(sh.otheritem() / 60.0)
Aktuell stehen zusätzlich zum Python Standard Sprachumfang folgende Packages bzw. SmartHomeNG Libraries zur Nutzung zur Vefügung:
shtime - die SmartHomeNG Library mit Zeit- und Datumsfunktionen
items - die SmartHomeNG Library mit Funktionen zum Umgang mit Items
math - das Python Package mit mathematischen Funktionen
uf - geladene Userfunctions
Für eval Ausdrücke können auch Relative Item Referenzen genutzt werden. Dann müssen Bezüge auf andere Items nicht mehr absolut angegeben werden, sondern können sich relativ auf andere Items beziehen.
Tipp
Im Abschnitt Logiken ist auf der Seite Feiertage, Daten und Zeiten beschrieben, welche Feiertags- und Datums-Funktionen in Logiken benutzt werden können. Diese Funktionen können auch in eval Attributen genutzt werden können.
Tipp
Im Abschnitt Beispiele sind auf der Seite eval und eval_trigger Beispiele weitere ausführliche Beispiele zu finden.
Nutzung von Userfunctions
Bei komplexeren Berechnungen kann es sinnvoll sein, diese in eine Userfunction auszulagern und im eval Ausdruck nur die Userfunction aufzurufen. Das bietet sich besonders an, wenn die gleiche Berechnung in mehreren Items durchgeführt werden soll.
Ein weiterer Vorteil von Userfunctions ist, dass Userfunctions modifiziert und neu geladen werden können, ohne SmartHomeNG komplett neu starten zu müssen. Das hilft besonders während der Entwicklung.
Eval Syntax
Der Syntax eines eval Ausdrucks ist der Syntax einer Python conditional expression
Dieser Syntax wird bei den Item Attributen eval, on_change und on_update verwendet.
Zu beachten ist, dass der Syntax einer if-Bedingung in einer Python conditional Expression folgender ist:
eval: <expression-if-true> if <condition> else <expression-if-false>
Beispiel:
eval: value if value>0 else 0
Die Expression setzt den Item-Wert auf den bisherigen Wert, falls er >0 ist, sonst wird der Wert auf 0 gesetzt. Damit findet eine Zuweisung statt und on_change bzw. on_update Trigger werden ausgelöst.
Wenn das Beispiel folgendermaßen formuliert wird:
eval: 0 if value<0 else None
Hätte es auf den Item-Wert letztlich die selben Auswirkungen: Hier wird der Item-Wert auf 0 gesetzt, falls der Wert <0 ist, sonst (None) wird keine Aktion ausgeführt (damit bleibt der Wert unverändert erhalten). Damit werden on_change bzw. on_update Trigger nur ausgelöst, wenn der Wert vorher <0 war. Bei Erhalt des Wertes (None), werden keine Trigger ausgelöst.
Attribut eval_trigger
Das Attribut eval_trigger legt eine Abhängigkeit von anderen Items fest. Sobald sich diese im Wert ändern, wird eine Neuberechnung gestartet. Das obige Beispiel könnte so erweitert werden:
TemperaturFahrenheit:
type: num
TemperaturCelsius:
# Formel (°F - 32) x 5/9 = °C
type: num
eval: (sh.TemperaturFahrenheit() - 32 ) * 5 / 9 # Aus 68°F werden somit 20°C
eval_trigger: TemperaturFahrenheit
Hier gibt es nun ein Attribut eval_trigger mit dem Item Namen TemperaturFahrenheit. Sobald sich dieses Item ändert, wird auch der Wert von TemperaturCelsius neu berechnet.
Im Attribut eval_trigger kann eine Liste mehrerer Items angegeben werden.
(Die Items müssen für das alte .conf Format jeweils durch ein ‘|’ voneinander getrennt werden.)
Der Ausdruck unter **eval* wird neu berechnet, wenn sich eines dieser Items verändert. Die Items können auch mit
einem Stern generalisiert werden. temperatur.\*
bedeutet, dass alle Kinderitems des Temperatur-Items zum
Evaluieren des Items führen. Oder \*.trigger
sorgt dafür, dass das Item durch alle Kind-Items mit dem
Namen “trigger” aktualisiert werden kann, also z.B. durch temperatur.trigger
, Licht.OG.trigger
, etc.
Seit SmartHomeNG v1.3 können für eval_trigger auch Relative Item Referenzen genutzt werden. Dann müssen Bezüge auf andere Items nicht mehr absolut angegeben werden sondern können sich relative auf andere Items beziehen.
Bemerkung
Ein häufiger Fehler bei der Nutzung von eval im Zusammenspiel mit eval_trigger ist, bei eval_trigger auch den vollen Python-Pfad zu einem SmartHomeNG Item zu verwenden, wie im eval Ausdruck.
Richtig ist es, bei eval_trigger nur den Item-Pfad zu nutzen (ohne führendes sh. und ohne folgende ()).
Korrekt:
eval: sh. my.item () oder sh.my.item.property.value
eval_trigger: my.item | my.other.item
Falsch:
eval: sh.my.item
eval_trigger: sh. my.item | sh. my.other.item
Attribut eval_on_trigger_only
Mit dem Attribut eval_on_trigger_only wird die Auswertung des eval Ausdrucks übersprungen, wenn dessen Auswertung nicht durch einen definierten eval_trigger erfolgt ist.
Raum:
Temperatur:
type: num
name: average temperature
eval: avg
eval_trigger:
- room_a.temp
- room_b.temp
Temperatur2:
type: num
name: average temperature
eval: avg
eval_on_trigger_only: true
eval_trigger:
- room_a.temp
- room_b.temp
Bemerkung
Wichtig anzumerken ist, dass die Nutzung der Funktionen, die eval_trigger Werte zur Berechnung verwenden (sum, avg, min, max, and und or) eingeschränkt wird, wenn eval_on_trigger_only gesetzt ist.
Wenn im vorhergehenden Beispiel dem Item Temperatur - z.B. per Logik - der Wert 5 zugewiesen wird, löst das die Berechnung der Durchschnittstemperatur der beiden Trigger aus.
Wenn dem Item Temperatur2 per Logik der Wert 5 zugewiesen wird, wird die Auswertung des eval Ausdrucks übersprungen und statt dessen der Wert des Items auf 5 gesetzt.
Gemeinsame Verwendung von eval und on_... Item Attributen
Bei Verwendung des eval Attributes zusammen mit on_change oder on_update in der selben Item Definition ist zu beachten, dass value unterschiedliche Werte hat/haben kann.
Im Ausdruck des eval Attributes hat value den alten Wert des Items. Nach Abschluss dieser Berechnung, wird dem Item das Ergebnis zugewiesen. Anschließend werden die Ausdrücke für on_change und on_update berechnet. Zu diesem Zeitpunkt hat das Item (und damit value) bereits den neuen Wert.
Wenn in eval Ausdrücken in on_change oder on_update Attributen auf den alten Wert des Items zugegriffen werden soll, muss dazu die Item Funktion prev_value() oder das Item Property property.last_value genutzt werden. Auf den alten Wert des aktuellen Items kann ohne die Angabe der vollständigen Item Pfades durch den Ausdruck sh..self.prev_value() zugegriffen werden.
Achtung
Bei eval Ausdrücken (wie sie in den Item Attributen eval, on_update und on_change verwendet werden) ist zu beachten, dass bei Verwendung von if auch immer ein else Zweig angegeben werden muss!
Wenn man jedoch ein Item nur verändern möchte wenn die if Bedingung erfüllt ist und sonst unverändert lassen möchte, muss als else Zweig der Ausdruck else None angegeben werden. None bewirkt, dass das Item unverändert bleibt, und somit auch keine Trigger ausgelöst werden.
Diese Art, per None
Werte nicht zuzuweisen, funktioniert nur bei eval
; bei anderen Attributen wie z.B. cycle
kann dies nicht genutzt werden.
Abfrage des Auslösers eines eval Ausdrucks
Zu dem Zeitpunkt, wo ein eval Ausdruck ausgeführt wird, bezieht sich das Property last_update_by
nicht auf
die aktuellste Auslösung des Items, sondern auf das letzte Update davor. Möchte man nun aber abfragen, durch welches
Item, Plugin oder durch welche Logik die Ausführung des eval Ausdrucks angestoßen wurde,
muss das seit SmartHomeNG 1.9.1 implementierte Property last_trigger_by
genutzt werden.
Dabei findet folgender zeitlicher Ablauf statt:
Aktualisieren des Itemwerts oder Veränderung eines Triggeritems (eval_trigger)
Setzen und Aktualisieren der
last_trigger_by
und dazu passenden PropertiesAusführen des eval Ausdrucks
Ist das Ergebnis des eval Ausdrucks None, passiert nichts weiter. Das Item wird nicht aktualisiert,
last_update_by
ändert sich ebenfalls nicht.Ist das Ergebnis des eval Ausdrucks ein erlaubter Wert, wird dieser ins Item geschrieben.
last_update_by
und/oderlast_change_by
werden entsprechend aktualisiert.
Details zu den verschiedenen Abfragemöglichkeiten sind unter Properties zu finden.
Achtung
Möchte man in einem eval Ausdruck abfragen, wodurch der Ausdruck ausgelöst wurde, muss property.last_trigger_by genutzt werden. Das property.last_update_by wird erst danach (oder bei None gar nicht) aktualisiert.
Tipp
War die Auflösung eines eval Ausdrucks nicht erfolgreich (weil z.B. die Syntax falsch ist oder ein Item nicht
gefunden werden konnte), wird beim last_trigger_by
den Caller- und Source-Angaben noch ein None (als „dest“) hinten
angehängt. Der Wert beinhaltet somit <caller>:<source>:None
.