# 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_value` wird 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. Aus demselben Grund heißen Zeit-Auslöser **„ab 16:30"** und nicht „gleich 16:30". Ein Gleichheitsvergleich wäre nur in genau einer Minute wahr — fällt der Runner in dieser Minute aus, ist die Automatik für den Tag verloren. „Ab 16:30" bleibt bis Mitternacht wahr, ausgelöst wird trotzdem nur einmal. Die breiten Zeitfenster in `auto_watering.py` folgen derselben Überlegung. `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.sql` einmal eingespielt * In `../deviceDiscovery/config.ini` muss **`clear_tables = false`** stehen. Discovery schreibt mit `ON DUPLICATE KEY UPDATE` auf den URLs, das Leeren ist unnötig — ein `TRUNCATE` würde dagegen die Geräte-IDs neu vergeben, und die Automatiken zeigen per Fremdschlüssel genau auf diese IDs. ## Einrichten ```bash 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.