Zeit-Ausloeser: "um" ergaenzt, Sonnenstand vervollstaendigt

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>
This commit is contained in:
2026-08-31 12:30:31 +02:00
co-authored by Claude Opus 5
parent 5f643b9844
commit ee417f302f
4 changed files with 91 additions and 39 deletions
+35 -15
View File
@@ -34,12 +34,21 @@ function meshDb()
* innerHTML ("≠", "&gt;") an den Server, wo eine Whitelist mit "!=" stand:
* jede Bedingung "ungleich" wurde still zu "gleich".
*
* Bei Zeit und Datum gibt es bewusst kein "gleich", sondern "ab" und "vor".
* "Uhrzeit = 16:30" waere nur in genau der einen Minute wahr - faellt der
* Runner in dieser Minute aus, ist die Automatik fuer den Tag verloren. "ab
* 16:30" bleibt bis Mitternacht wahr; ausgeloest wird trotzdem nur einmal,
* weil nur die steigende Flanke zaehlt. Dieselbe Ueberlegung steht hinter den
* breiten Zeitfenstern in auto_watering.py.
* Bei Zeit und Datum heissen die Operatoren "um", "ab" und "vor":
*
* um 16:30 genau in dieser Minute. Der uebliche Fall - einmal taeglich
* zu einem festen Zeitpunkt.
* ab 16:30 ab da bis Mitternacht wahr. Ausgeloest wird trotzdem nur
* einmal, weil nur die steigende Flanke zaehlt; dafuer kostet
* ein verpasster Takt nicht den ganzen Tag. Dieselbe
* Ueberlegung steht hinter den breiten Zeitfenstern in
* auto_watering.py.
* vor 16:30 bis dahin wahr, danach nicht mehr.
*
* Beim Sonnenauf- und -untergang ist der Wert ein Versatz, der davor oder
* danach liegen kann - deshalb dieselben drei Faelle noch einmal 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.
*/
function operatorsForType($type)
{
@@ -50,9 +59,9 @@ function operatorsForType($type)
case "time":
case "date":
case "datetime":
return [">=", "<"];
return ["=", ">=", "<"];
case "deltatime": // Sonnenauf-/-untergang: Wert ist ein Versatz
return ["+", "-"];
return ["+", "-", ">=+", ">=-", "<+", "<-"];
case "bool":
return ["="]; // JA/NEIN steht im Wertfeld, nicht im Operator
default:
@@ -96,19 +105,29 @@ function inputForType($type, $hasOptions)
}
/**
* Anzeigeform eines Operators. Bei Zeitangaben liest sich "ab"/"vor"
* verstaendlicher als ">="/"<", und bei Sonnenauf-/-untergang steht der
* Versatz dahinter: "ab + 00:30" heisst eine halbe Stunde danach.
* Anzeigeform eines Operators. Bei Zeitangaben liest sich "um"/"ab"/"vor"
* verstaendlicher als "="/">="/"<", und beim Sonnenstand steht das
* Vorzeichen des Versatzes dahinter: "ab + 00:30" heisst ab einer halben
* Stunde nach Sonnenaufgang.
*/
function operatorLabel($op, $type = "")
{
if ($type === "time" || $type === "date" || $type === "datetime") {
if ($type === "time" || $type === "datetime") {
if ($op === "=") return "um";
if ($op === ">=") return "ab";
if ($op === "<") return "vor";
}
if ($type === "date") {
if ($op === "=") return "am";
if ($op === ">=") return "ab";
if ($op === "<") return "vor";
}
if ($type === "deltatime") {
if ($op === "+") return "ab +";
if ($op === "-") return "ab -";
$beschriftung = ["+" => "+", "-" => "-", ">=+" => "ab +", ">=-" => "ab -",
"<+" => "vor +", "<-" => "vor -"];
if (isset($beschriftung[$op])) {
return $beschriftung[$op];
}
}
return $op === "!=" ? "" : $op;
}
@@ -409,7 +428,8 @@ function saveAutomation($data)
if ($stateId <= 0) {
throw new InvalidArgumentException("Eine Bedingung hat keinen Messwert.");
}
if (!in_array($operator, ["=", "!=", ">", "<", ">=", "<=", "+", "-"], true)) {
if (!in_array($operator, ["=", "!=", ">", "<", ">=", "<=",
"+", "-", ">=+", ">=-", "<+", "<-"], true)) {
throw new InvalidArgumentException("Unbekannter Operator: " . $operator);
}
$positions[$group] = ($positions[$group] ?? -1) + 1;