Logiken under construction
Eine Logik besteht aus einem Python Skript sowie einer Reihe von Parametern die den Aufruf (das Triggern) der Logik steuern. Eine Logik kan während der Laufzeit von SmartHomeNG geladen und entladen werden. Dadurch sind Veränderungen ein einer Logik möglich, ohne SmartHomeNG neu starten zu müssen.
Einführung
Das eigentliche Python Skript einer Logik muss im Verzeichnis ../logics
der SmartHomeNG Installation abgelegt
werden. Damit die Logik getriggert und ausgeführt wird, muss sie zusätzlich in der Konfigurationsdatei
../etc/logic.yaml
konfiguriert werden. Hier wird festgelegt, unter welchen Bedingungen eine bestimmte Logik
auszuführen ist.
Wenn eine Logik mit der Admin GUI erstellt wurde, ist sie nach dem ersten erfolgreichen Laden pausiert (disabled). Damit die Logik ausgeführt werden kann, muss sie zuerst mit dem „Play“-Button enabeld werden. (Der „Play“-Button wechselt dabei zum „Pause“-Button.)
Behandlung von Fehlern in der Logik
Syntaktische Fehler
Wenn eine Logik geladen wird, entweder beim Start von SmartHomeNG oder durch die Admin GUI, wird das Python Skript, wie ein normales Python Programm, in einen Bytecode übersetzt. Falls hierbei ein grober syntaktischer Fehler auftritt, wird die Logik nicht geladen und es wird ein entsprechender Fehler geloggt.
Beispiel: Folgende Test Logik
#!/usr/bin/env python3
# test_logic.py
logger.warning("Start der Logik")
Hier steht Müll
logger.warning("Ende der Logik")
erzeugt beim laden/übersetzen folgenden Logeintrag:
2022-01-24 12:51:26 ERROR lib.logic Exception: invalid syntax (test_logic.py, line 6)
Traceback (most recent call last):
File "/usr/local/shng_dev/lib/logic.py", line 1034, in _generate_bytecode
self.bytecode = compile(code, self.pathname, 'exec')
File "/usr/local/shng_dev/logics/test_logic.py", line 6
Hier steht Müll
^
SyntaxError: invalid syntax
Laufzeit Fehler
Nachdem eine Logik erfolgreich geladen wurde, können bei der Ausführung der Logik Laufzeit Fehler auftreten. Falls ein Laufzeitfehler nicht innerhalb der Logik abgefangen wird, führt er zur Beendigung des aktuellen Laufes der Logik und es wird ein entsprechender Fehler geloggt. Die Logik bleibt jedoch geladen und wird, wenn sie getriggert wird, erneut ausgeführt.
Beispiel: Folgende Test Logik
#!/usr/bin/env python3
# test_logic.py
logger.warning("Start der Logik")
var = int('abc')
logger.warning("Ende der Logik")
erzeugt zur Laufzeit folgenden Logeintrag:
2022-01-24 13:55:14 ERROR logics.test_logic In der Logik ist ein Fehler aufgetreten:
Logik 'test_logic', Datei '/usr/local/shng_dev/logics/test_logic.py', Zeile 6
Hauptroutine der Logik, Exception: invalid literal for int() with base 10: 'abc'
Template für eine neue Logik
Eine neue Logik sollte möglichst auf der folgenden Vorlage logic.tpl
aufbauen.
Die Template Datei ist im Verzeichnis logics/
abgelegt:
#!/usr/bin/env python3
#
# This file contains a logic for use with SmartHomeNG
#
# Name of the logic: example_logic.py
#
# This logic performs the following function(s):
#
# ...
#
# The following triggers should be defined in ../etc/logic.yaml:
#
# watch_item = <item1> | <item2> | ...
# crontab = init = Init
# cycle = 600
#
Um zum Beispiel eine Logik example
zu erzeugen, muss zuerst die Datei logics/logic.tpl
auf die
Datei logics/example.py
kopiert werden und in der erstellten Datei der eigentliche Code der Logik erfasst werden.
Anschließend muss noch in der Konfigurationsdatei etc/logic.yaml
die Konfiguration für die Logik festgelegt
werden.
Die Minimalkonfiguration sieht für das Beispiel folgendermaßen aus:
example:
filename: example.py
Der Name der Logik wird durch den Namen des Abschnitts example
in der Konfigurationsdatei festgelegt. Unter diesem
Namen wird die Logik innerhalb von SmartHomeNG angesprochen. Der Parameter filename
legt fest, in welcher
Datei der Code für die Logik example
gespeichert ist. Dafür kann im Prinzip ein beliebiger Dateiname gewählt
werden, solange die Extension .py
ist. Um mögliche Verwirrungen zu vermeiden, wird jedoch empfohlen den
Namen der Logik und den Namen der Datei gleich zu wählen. Generell sollten Dateinamen nur aus Kleinbuchstaben
bestehen, da je nach verwendetem Betriebssystem das Dateisystem evtl. Case sensitiv ist und Example.py
eine
andere Datei sein kann als example.py
.
Erst mit der Existenz dieser Konfiguration kann die Logik gestartet werden. Die Logik würde zwar noch nicht durch ein normaler Ereignis innerhalb von SmartHomeNG getriggert, da keine Trigger definiert sind, die Logik kann jedoch aus der Admin GUI getriggert werden.
Wenn die Logik zum Beispiel beim Start von SmartHomeNG getriggert werden soll, so muss noch der folgende crontab
Parameter angebeben werden:
example:
filename: example.py
crontab: init
Verlassen einer Logik
Normalerweise wird der aktuelle Lauf einer Logik dadurch beendet, dass das Ende des Codes der Hauptroutine erreicht wird. In einigen Fällen kann es jedoch sinnvoll sein, die Logik mitten aus dem Code heraus oder as einer Funktion heraus zu beenden/zu verlassen.
Dafür kann eine spezielle Exception ausgelöst werden. Das geschieht mit dem Befehl raise LeaveLogic()
.
Details hierzu sind in der Referenz zu finden.
Beispiele
Die folgende Beispielkonfiguration definiert 4 Logiken:
Die erste Logik mit Namen
InitSmartHomeNG
befindet sich in der Dateilogics/initsmarthomeng.py
. Das Attributcrontab: init
weist SmartHomeNG an diese Logik direkt nach dem Start auszuführen.Die zweite Logik mit dem Namen
Hourly
befindet sich in der Dateilogics/time.py
und das Attributcycle: 3600
weist SmartHomeNG an die Logik alle 3600 Sekunden (jede Stunde) auszuführen.Die dritte Logik mit Namen
Gate
befindet sich in der Dateilogics/gate.py
und das Attributwatch_item: gate.alarm
weist SmartHomeNG an die Logik auszuführen, wenn der Wert des Items gate.alarm sich ändert.Die vierte Logik mit Namen
disks
befindet sich in der Dateilogics/disks.py
. Der crontab Eintrag weist SmartHomeNG an diese Logik alle 5 Minuten auszuführen. Der Parameterusage_warning
ist ein benutzerdefinierter Parameter, der in der Logik verwendet wird, um einen Schwellwert zu definieren.
InitSmarthomeNG:
filename: initsmarthomeng.py
crontab: init
Hourly:
filename: time.py
cycle: 3600
Gate:
filename: gate.py
watch_item: gate.alarm # monitor for changes
disks:
filename: disks.py
# 'crontab: run at start and every 5 minutes'
crontab:
- init
- '0,5,10,15,20,25,30,35,40,45,50,55 * * *'
usage_warning: 500