Bei Uhrzeit und Datum gab es nur "ab" und "vor". Der haeufigste Fall - eine Aktion genau um 16:30 - liess sich damit gar nicht ausdruecken. "um" ist jetzt der erste Eintrag und damit die Vorbelegung. Der Hinweis von frueher bleibt trotzdem richtig und steht in der README: "um" trifft nur eine einzige Minute, faellt der Runner ausgerechnet in dieser Minute aus, ist die Automatik fuer den Tag verloren. "ab" holt der naechste Takt nach. Wer beides will, hakt force_once an. Beim Sonnenauf- und -untergang fehlte die halbe Tabelle: der Versatz kann davor oder danach liegen, und verglichen werden kann davor, danach oder genau. Statt zwei gibt es jetzt sechs Operatoren - "+", "-", "ab +", "ab -", "vor +", "vor -". Das Vorzeichen steckt im Operator, weil der Editor eine einzige Auswahlliste zeigt und nicht zwei Bedienelemente fuer eine Angabe. Rutscht ein Versatz rechnerisch ueber den Tagesrand (Sonnenaufgang 05:34 minus sechs Stunden), bleibt es beim Tagesrand statt auf die andere Seite von Mitternacht zu springen - "kurz vor Sonnenaufgang" soll nicht ploetzlich gestern abend bedeuten. Der Editor brauchte keine Aenderung: er liest Wert und Beschriftung der Operatoren aus dem Geraetekatalog, statt sie selbst zu kennen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.3 KiB
AutoActions
Automatiken, die im Web-UI unter „Automatismen" angelegt werden und hier ausgeführt werden: wenn Bedingung, dann Kommando.
Browser Datenbank homeMesh Runner
────────────────────── ───────────────────────── ────────────────────
Karte „Automatismen" ──▶ automations ──▶ autoaction_runner.py
ajax/AutoAction.php automation_conditions MQTT / HTTP / Tahoma
restricted/automations.php automation_actions ──▶ Geräte
js/solar/autoActionFuncs.js automation_action_params
automation_log
calendar_days ◀── fetch_calendar.py
Wie eine Automatik aufgebaut ist
Eine Automatik hat Auslöser, Rahmenbedingungen und Aktionen.
Ein Auslöser vergleicht einen Messwert (actor_states) mit einer Schwelle.
Mehrere Auslöser werden über group_no verknüpft: gleiche Nummer heißt UND,
verschiedene Nummern heißen ODER — ausgewertet wird any(all(gruppe)). Im
Editor ist eine Gruppe ein gerahmter Block mit eigenem „+ Bedingung", zwischen
den Blöcken steht ein ODER. Die Klammerung ist damit gezeichnet und nicht bloß
vereinbart, und darunter steht derselbe Ausdruck noch einmal als Satz.
Eine Aktion ist ein Kommando (actor_commands) mit einem Wert je Parameter
(command_parameters) — nicht vier feste Spalten „Wert 1" bis „Wert 4",
sondern so viele Zeilen, wie das Gerät Parameter hat.
Die Rahmenbedingungen (Wochentage, Zeitfenster, Ferien, Feiertage) sagen, wann die Automatik überhaupt hinsehen darf.
Warum ein Dauerläufer und kein Cronjob
Zwei Gründe:
- Schwellwert-Auslöser sollen greifen, wenn die MQTT-Nachricht hereinkommt, nicht erst im nächsten Minutenraster.
actor_states.current_valuewird sonst von niemandem fortgeschrieben — es wird beim Geräte-Discovery einmal gesetzt und danach nie wieder. Ein zustandsloser Cronjob hätte gar nichts, womit er vergleichen könnte. Der Runner pflegt den Wert nebenbei mit (gedrosselt auf einmal je Minute), wovon auch der Editor profitiert: er zeigt neben jedem Messwert den aktuellen Stand.
Nur die steigende Flanke
automations.cond_met hält fest, ob die Bedingung beim letzten Durchlauf schon
erfüllt war. Ohne das würde „Temperatur über 22 Grad" bei jedem Takt erneut
feuern. Verlässt die Automatik ihr Zeitfenster, wird die Flanke
zurückgesetzt, damit sie im nächsten Fenster wieder steigen kann.
Zeit-Auslöser gibt es in drei Formen:
| wahr, wenn | |
|---|---|
um 16:30 |
genau in dieser Minute |
ab 16:30 |
von da an bis Mitternacht |
vor 16:30 |
bis dahin |
Ausgelöst wird in allen drei Fällen nur einmal, eben wegen der Flanke. ab
ist trotzdem das robustere: fällt der Runner in genau der Minute aus, auf die
um zeigt, ist die Automatik für den Tag verloren — bei ab holt der nächste
Takt es nach. Wer um braucht und den Ausfall nicht riskieren will, hakt
zusätzlich force_once an. Die breiten Zeitfenster in auto_watering.py
folgen derselben Überlegung.
Beim Sonnenauf- und -untergang ist der Wert ein Versatz, und der kann davor
oder danach liegen — deshalb dieselben drei Fälle mal zwei: + 00:30 eine
halbe Stunde nach Sonnenaufgang, ab - 00:30 ab einer halben Stunde davor,
vor + 00:30 bis eine halbe Stunde danach. Rutscht ein Versatz rechnerisch
über den Tagesrand, bleibt es beim Tagesrand — „kurz vor Sonnenaufgang" soll
nicht plötzlich gestern Abend bedeuten.
force_once („am Ende des Zeitraums auf jeden Fall ausführen") greift, wenn
das Fenster zugeht und in diesem Fenster noch nichts passiert ist.
Transporte
Welcher Weg zum Gerät führt, entscheidet die URL des Aktors in actors:
| URL | Messwert (actor_states.url) |
Kommando |
|---|---|---|
mqtt://… |
vollständiges Topic, abonniert | publiziert auf das Parameter-Topic |
http://… |
Feldname in der JSON-Antwort, gepollt | Parameter als Abfrageargumente |
io://… |
Tahoma-Statusname, gepollt | exec/apply an die Tahoma-Box |
Logic |
gerechnet: Uhrzeit, Datum, Sonne | – |
Alle vier stehen in transports.py. Eine fünfte Geräteart kommt als weitere
Klasse dazu; sie braucht passt(), zustaende_lesen() und senden().
Bei HTTP heißen die Schaltbefehle nicht so wie in der Datenbank — dafür gibt es
in HTTPTransport eine kleine Übersetzungstabelle (turn_on → on=true).
Das ist die Stelle, die beim Anschluss neuer HTTP-Geräte wächst.
Voraussetzungen
- Python 3 mit
pymysql,requests,paho-mqtt homeMesh_automations.sqleinmal eingespielt- In
../deviceDiscovery/config.inimussclear_tables = falsestehen. Discovery schreibt mitON DUPLICATE KEY UPDATEauf den URLs, das Leeren ist unnötig — einTRUNCATEwürde dagegen die Geräte-IDs neu vergeben, und die Automatiken zeigen per Fremdschlüssel genau auf diese IDs.
Einrichten
cp config.ini.example config.ini # ausfüllen: Datenbank, MQTT, Tahoma
python3 fetch_calendar.py # Feiertage und Ferien holen
python3 autoaction_runner.py --once --dry-run --verbose # Probelauf
--dry-run schaltet nichts, protokolliert aber jedes Kommando, das geschickt
würde. --once macht einen einzigen Durchlauf.
Im Dauerbetrieb wird autoaction_runner.py beim Booten gestartet (auf der
Synology über den Aufgabenplaner, Ereignis „Hochfahren", als root). Er
verbindet sich selbst neu, wenn MQTT wegbricht, und lädt das Regelwerk nach,
sobald im Browser etwas gespeichert wurde — ein Neustart nach jeder Änderung
ist nicht nötig.
fetch_calendar.py gehört einmal jährlich in den Cron:
0 4 1 1 * /usr/bin/python3 /volume1/web/smart/restricted/autoActions/fetch_calendar.py
Ein zusätzlicher Lauf im Herbst schadet nicht — die Ferientermine des übernächsten Schuljahres stehen erst später fest.
Nachsehen, was passiert ist
automation_log hält je Auslösung fest, ob sie durchlief (fired), wegen
force_once nachgeholt wurde (forced) oder scheiterte (error, mit Grund in
detail). Einträge älter als 30 Tage räumt der Runner selbst weg.