Ferien und Feiertage dreiwertig, dazu eine Tagessperre

"An Wochenenden und Feiertagen" liess sich bisher gar nicht schreiben.
Die Wochentagsmaske kennt nur Samstag und Sonntag, und ein Feiertag am
Dienstag ist fuer sie eben ein Dienstag; on_holiday war ja/nein und
konnte nur wegnehmen, nie hinzufuegen.

on_vacation und on_holiday tragen deshalb jetzt drei Werte: 0 nie,
1 egal (Vorgabe), 2 zusaetzlich. Der dritte zaehlt wie ein angehakter
Wochentag - Sa+So angehakt und "Feiertage: zusaetzlich" ergibt den
gewuenschten Fall, und mit gar keinem angehakten Tag sogar "nur an
Feiertagen".

In tag_passt() wird erst geoeffnet, dann gesperrt: ein Verbot schlaegt
eine Erweiterung. Wer in den Ferien nie laeuft und an Feiertagen
zusaetzlich, laeuft an einem Feiertag in den Ferien nicht - andersherum
liesse sich "nie" nicht mehr verlassen.

Dazu once_per_day: nach dem Ausloesen bis Mitternacht Ruhe. Fuer alles,
was man hinterher von Hand wieder anders stellt - ein Rollladen, den man
um acht zugezogen hat, soll nicht um neun von selbst wieder auffahren,
weil eine Wolke weiterzieht und die Helligkeitsschwelle ein zweites Mal
steigt. Die Sperrzeit taugte dafuer nicht: sie zaehlt Sekunden und
muesste auf 86400 stehen, womit eine Automatik, die heute um 07:00:05
lief, morgen um 07:00:00 noch gesperrt waere und einen ganzen Tag
ausfiele. Gefragt wird deshalb nach dem Datum von last_run - dieselbe
Funktion, die auch force_once benutzt, nur mit umgekehrtem Vorzeichen.

Die Spalten bleiben TINYINT und tragen die 2 ohne Weiteres; die
vorhandenen Zeilen stehen auf 0 oder 1 und behalten damit genau ihre
bisherige Bedeutung. Umzurechnen gibt es nichts. rahmen_erweitern.sql
setzt nur Kommentare und legt once_per_day an.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 20:07:36 +02:00
co-authored by Claude Opus 5
parent 09ce5c56c7
commit 32e571099b
3 changed files with 173 additions and 5 deletions
+56 -1
View File
@@ -30,7 +30,7 @@ Eine Aktion ist ein Kommando (`actor_commands`) mit einem Wert je Parameter
sondern so viele Zeilen, wie das Gerät Parameter hat.
Die Rahmenbedingungen (Wochentage, Zeitfenster, Ferien, Feiertage) sagen, wann
die Automatik überhaupt hinsehen darf.
die Automatik überhaupt hinsehen darf — siehe [Der Rahmen](#der-rahmen).
## Warum ein Dauerläufer und kein Cronjob
@@ -114,6 +114,55 @@ und `vor` verschiebt sich der wahre Bereich entsprechend mit.
`force_once` („am Ende des Zeitraums auf jeden Fall ausführen") greift, wenn
das Fenster zugeht und in diesem Fenster noch nichts passiert ist.
## Der Rahmen
Vor jeder Auswertung fragt `tag_passt()`, ob der heutige Tag überhaupt zählt.
Drei Dinge entscheiden das: die Wochentagsmaske (`weekdays`, ein Bit je Tag,
Montag ist Bit 0), und Ferien und Feiertage aus `calendar_days`.
Ferien und Feiertage sind **dreiwertig**, nicht ja/nein:
| Editor | `on_vacation` / `on_holiday` | heißt |
|---|---|---|
| **nie** | `0` | an solchen Tagen läuft die Automatik nicht |
| **egal** | `1` (Vorgabe) | der Tag ändert nichts |
| **immer** | `2` | zählt wie ein angehakter Wochentag |
Die ersten beiden gab es immer; „werktags" ist `weekdays = 31` und
`on_holiday = 0`. Der dritte Wert kam dazu, weil sich **„an Wochenenden und
Feiertagen" sonst gar nicht schreiben ließ**: die Wochentagsmaske kennt nur
Samstag und Sonntag, und ein Feiertag am Dienstag ist für sie eben ein
Dienstag. Mit `2` genügt Sa+So angehakt und „Feiertage: immer", der Dienstag
kommt dann über den Kalender herein. Und weil `2` allein trägt, ergibt
`weekdays = 0` mit „Feiertage: immer" ein **nur an Feiertagen** — das ging
vorher gar nicht.
Erst wird geöffnet, dann gesperrt: **ein Verbot schlägt eine Erweiterung.**
Wer in den Ferien nie läuft und an Feiertagen zusätzlich, läuft an einem
Feiertag in den Ferien nicht. Andersherum ließe sich „nie" nicht mehr
verlassen.
Die Spalten sind `TINYINT` geblieben und tragen die `2` ohne Weiteres; die
vorhandenen Zeilen stehen auf `0` oder `1` und behalten damit genau ihre
bisherige Bedeutung. Umzurechnen gibt es nichts, die Migration
(`rahmen_erweitern.sql`) setzt nur Kommentare und legt `once_per_day` an.
## Nur einmal am Tag
`once_per_day` sperrt eine Automatik nach dem Auslösen bis Mitternacht.
Gedacht für alles, was man hinterher von Hand wieder anders stellt. Der
Rollladen fährt morgens auf; um acht zieht man ihn nochmal zu, weil die Sonne
blendet — und um neun zieht eine Wolke weiter, die Helligkeitsschwelle steigt
ein zweites Mal, und die Automatik funkt dazwischen. Genau das verhindert der
Haken.
Die Sperrzeit taugt dafür nicht. Sie zählt Sekunden und müsste auf 86 400
stehen; eine Automatik, die heute um 07:00:05 lief, wäre morgen um 07:00:00
noch gesperrt und fiele einen ganzen Tag aus. Gefragt wird deshalb nach dem
**Datum** von `last_run`, nicht nach dem Abstand — dieselbe Funktion
(`lief_heute`), die auch `force_once` benutzt, nur mit umgekehrtem Vorzeichen.
## Sperrzeit
Die Flanke allein schützt nicht gegen einen Messwert, der um die Schwelle
@@ -324,6 +373,7 @@ Parameter dort keine eigene URL — ihr Name *ist* der Platzhalter.
```bash
cp config.ini.example config.ini # ausfüllen: Datenbank, MQTT, Tahoma
mysql -h 127.0.0.1 -P 3310 -u homeMesh -p homeMesh < automatik_ausloeser.sql
mysql -h 127.0.0.1 -P 3310 -u homeMesh -p homeMesh < rahmen_erweitern.sql
python3 fetch_calendar.py # Feiertage und Ferien holen
python3 autoaction_runner.py --once --dry-run --verbose # Probelauf
```
@@ -334,6 +384,10 @@ Messwerte darunter legt der Runner selbst an. Ohne das Skript läuft alles
Übrige weiter, es fehlt nur die Möglichkeit, eine Automatik als Auslöser zu
wählen.
`rahmen_erweitern.sql` gehört zum Rahmen: es beschriftet `on_vacation` und
`on_holiday` mit ihren drei Bedeutungen und legt `once_per_day` an. Beide
Skripte sind idempotent — ein zweiter Lauf schadet nicht.
`--dry-run` schaltet nichts, protokolliert aber jedes Kommando, das geschickt
würde. `--once` macht einen einzigen Durchlauf.
@@ -351,6 +405,7 @@ nicht im Web-Verzeichnis:
├── transports.py
├── fetch_calendar.py
├── automatik_ausloeser.sql einmalig, siehe Einrichten
├── rahmen_erweitern.sql einmalig, siehe Einrichten
└── config.ini Zugangsdaten, nicht im Git
```