From df2765b16ac02550e3314022811e1b55eeab1411 Mon Sep 17 00:00:00 2001 From: Moirtz Wagner Date: Thu, 3 Sep 2026 19:27:10 +0200 Subject: [PATCH] Runner merkt jetzt, wenn eine Bedingung geaendert wurde Die Signatur, an der er ein Neuladen festmacht, bestand aus Zeilenzahlen und MAX(changed). Beides bleibt gleich, wenn in der Weboberflaeche nur die Uhrzeit einer Bedingung verstellt wird: gespeichert wird durch Loeschen und Neueinfuegen, und automations.changed ruehrt sich nicht, weil sich in der Zeile selbst nichts aendert. Der Runner lief dann bis zum naechsten Neustart mit der alten Uhrzeit weiter - ohne dass irgendwo etwas schieflief, er wusste es schlicht nicht besser. Jetzt geht der Inhalt mit ein, als Summe der CRC32 je Zeile. Billig genug fuer die Pruefung alle 30 Sekunden. Neu dabei sind die Aktionsparameter, die vorher gar nicht drinstanden - eine geaenderte Zielhoehe einer Jalousie schlug also ebenso wenig durch. Nachgestellt mit einer Automatik ohne Aktionen: vorher blieb eine reine Bedingungsaenderung wirkungslos, danach loeste sie zwei Sekunden nach der Zielminute aus. Co-Authored-By: Claude Opus 5 --- autoActions/autoaction_runner.py | 42 +++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/autoActions/autoaction_runner.py b/autoActions/autoaction_runner.py index 3533884..9fec062 100644 --- a/autoActions/autoaction_runner.py +++ b/autoActions/autoaction_runner.py @@ -138,16 +138,50 @@ class Regelwerk: @staticmethod def signatur_lesen(db): """ - Woran der Runner merkt, dass er neu laden muss. `changed` allein - genuegt nicht: eine geloeschte Automatik veraendert den groessten - Zeitstempel nicht. Deshalb zaehlen die Zeilen mit - auch die der - Geraetetabellen, damit ein Discovery-Lauf ebenfalls durchschlaegt. + Woran der Runner merkt, dass er neu laden muss. + + `changed` allein genuegt nicht: eine geloeschte Automatik veraendert + den groessten Zeitstempel nicht. Die Zeilen zu zaehlen genuegt aber + auch nicht - die Weboberflaeche speichert eine Automatik, indem sie + deren Bedingungen und Aktionen loescht und gleich wieder einfuegt. Wer + nur die Uhrzeit einer Bedingung verstellt, aendert damit weder die + Zeilenzahl noch `changed`: ON UPDATE stoesst nur an, wenn sich in + automations wirklich eine Spalte aendert, und Name, Stockwerk und + Zeitfenster stehen ja noch genauso da. Der Runner lief dann bis zum + naechsten Neustart mit der alten Uhrzeit weiter, ohne dass irgendwo + etwas schieflief - er wusste es schlicht nicht besser. + + Deshalb geht jetzt der Inhalt mit ein, als Summe der CRC32 je Zeile. + Das ist kein Hash mit Sicherheitsanspruch, sondern ein billiger + Fingerabdruck - er wird alle paar Sekunden gebildet und darf nichts + kosten. Zwei Aenderungen, die sich in der Summe gegenseitig aufheben, + sind theoretisch denkbar und praktisch nicht zu erwarten. Die + Zeilenzahl steht trotzdem daneben, damit eine geloeschte und eine neu + angelegte Zeile nicht zufaellig gleich viel ergeben. + + Neu dabei sind die Aktionsparameter. Sie standen vorher gar nicht + drin: eine geaenderte Zielhoehe einer Jalousie schlug also ebenso + wenig durch. + + Die Zeilenzahlen der Geraetetabellen bleiben, damit ein + Discovery-Lauf weiterhin ein Neuladen ausloest. """ with db.cursor() as c: c.execute("""SELECT (SELECT COUNT(*) FROM automations) AS a, (SELECT UNIX_TIMESTAMP(MAX(changed)) FROM automations) AS t, (SELECT COUNT(*) FROM automation_conditions) AS b, + (SELECT COALESCE(SUM(CRC32(CONCAT_WS(':', + id, automation_id, group_no, position, + state_id, operator, value))), 0) + FROM automation_conditions) AS bs, (SELECT COUNT(*) FROM automation_actions) AS c, + (SELECT COALESCE(SUM(CRC32(CONCAT_WS(':', + id, automation_id, position, command_id))), 0) + FROM automation_actions) AS cs, + (SELECT COUNT(*) FROM automation_action_params) AS p, + (SELECT COALESCE(SUM(CRC32(CONCAT_WS(':', + action_id, parameter_id, value))), 0) + FROM automation_action_params) AS ps, (SELECT COUNT(*) FROM actor_states) AS d, (SELECT COUNT(*) FROM actor_commands) AS e""") return tuple(sorted(c.fetchone().items()))