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:
@@ -511,12 +511,41 @@ def im_zeitfenster(jetzt, von, bis):
|
||||
return a <= m <= b if a <= b else (m >= a or m <= b)
|
||||
|
||||
|
||||
#: Ferien und Feiertage sind dreiwertig, nicht ja/nein.
|
||||
NIE, EGAL, ZUSAETZLICH = 0, 1, 2
|
||||
|
||||
|
||||
def tag_passt(automatik, jetzt, kalender):
|
||||
if not automatik["weekdays"] & (1 << jetzt.weekday()):
|
||||
"""
|
||||
Faellt der heutige Tag in den Rahmen der Automatik?
|
||||
|
||||
Die Wochentage sind eine Maske, Ferien und Feiertage haben je drei
|
||||
Zustaende. Zwei davon gab es immer: EGAL (der Tag aendert nichts, die
|
||||
Vorgabe) und NIE (an solchen Tagen laeuft die Automatik nicht - so ist
|
||||
"werktags" gebaut). ZUSAETZLICH ist der dritte und zaehlt wie ein
|
||||
passender Wochentag.
|
||||
|
||||
Der Grund fuer den dritten: "Wochenenden und Feiertage" liess sich vorher
|
||||
gar nicht schreiben. Die Wochentagsmaske kennt nur Samstag und Sonntag,
|
||||
und ein Feiertag am Dienstag ist eben ein Dienstag. Mit ZUSAETZLICH
|
||||
genuegt Sa+So angehakt und "Feiertage: zusaetzlich" - der Dienstag kommt
|
||||
dann ueber den Kalender herein.
|
||||
|
||||
Reihenfolge: erst wird geoeffnet, dann gesperrt. Wer in den Ferien nie
|
||||
laufen soll und an Feiertagen zusaetzlich, laeuft an einem Feiertag in
|
||||
den Ferien nicht - ein Verbot schlaegt eine Erweiterung. Anders herum
|
||||
liesse sich "nie" nicht mehr verlassen.
|
||||
"""
|
||||
passt = bool(automatik["weekdays"] & (1 << jetzt.weekday()))
|
||||
if kalender["feiertag"] and automatik["on_holiday"] == ZUSAETZLICH:
|
||||
passt = True
|
||||
if kalender["ferien"] and automatik["on_vacation"] == ZUSAETZLICH:
|
||||
passt = True
|
||||
if not passt:
|
||||
return False
|
||||
if kalender["feiertag"] and not automatik["on_holiday"]:
|
||||
if kalender["feiertag"] and automatik["on_holiday"] == NIE:
|
||||
return False
|
||||
if kalender["ferien"] and not automatik["on_vacation"]:
|
||||
if kalender["ferien"] and automatik["on_vacation"] == NIE:
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -1150,7 +1179,10 @@ class Runner:
|
||||
erfuellt = gruppen_erfuellt(automatik, self.regelwerk, self.werte,
|
||||
jetzt, fenster)
|
||||
if erfuellt and not automatik["cond_met"]:
|
||||
if self.gesperrt(automatik, jetzt):
|
||||
if automatik.get("once_per_day") and self.lief_heute(automatik, jetzt):
|
||||
logger.debug("%s: lief heute schon, bis Mitternacht gesperrt",
|
||||
automatik["name"])
|
||||
elif self.gesperrt(automatik, jetzt):
|
||||
logger.debug("%s: Flanke faellt in die Sperrzeit, uebersprungen",
|
||||
automatik["name"])
|
||||
else:
|
||||
@@ -1200,6 +1232,21 @@ class Runner:
|
||||
|
||||
@staticmethod
|
||||
def lief_heute(automatik, jetzt):
|
||||
"""
|
||||
Hat die Automatik heute schon ausgeloest?
|
||||
|
||||
Zwei Stellen fragen danach. force_once will wissen, ob es am Ende des
|
||||
Fensters noch etwas nachzuholen gibt. once_per_day will das Gegenteil:
|
||||
einmal am Tag genuegt, danach ist bis Mitternacht Ruhe.
|
||||
|
||||
Letzteres ist fuer alles gedacht, was man hinterher von Hand wieder
|
||||
anders stellt. Ein Rollladen, den man um acht nochmal zugezogen hat,
|
||||
soll nicht um neun von selbst wieder auffahren, nur weil eine Wolke
|
||||
weiterzieht und die Helligkeitsschwelle ein zweites Mal steigt. Die
|
||||
Sperrzeit taugt dafuer nicht: sie zaehlt Sekunden und muesste auf
|
||||
einen Tag stehen, womit sie am naechsten Morgen den Termin knapp
|
||||
verfehlen wuerde.
|
||||
"""
|
||||
letzter = automatik.get("last_run")
|
||||
return bool(letzter) and letzter.date() == jetzt.date()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user