diff --git a/ajax/AutoAction.php b/ajax/AutoAction.php index 5575ff8..7be0f04 100644 --- a/ajax/AutoAction.php +++ b/ajax/AutoAction.php @@ -469,18 +469,21 @@ $nutzdaten = json_encode([ benutzen - Zeit - und trotzdem entgegengesetzt wirken: die Sperre bremst die Wiederholung, die Haltezeit den ersten Lauf. - Freie Minuten statt einer Auswahlliste: Wonach man sucht, haengt am - Messwert. Die Zeile über dem Rahmen rechnet beim Tippen mit und - zeigt "erst nach 3,5 Std." - dort steht die lesbare Fassung, hier - die eingebbare. + Frei einstellbar statt aus einer Auswahlliste: Wonach man sucht, + hängt am Messwert - eine offene Tür fällt nach zwei Minuten auf, + ein laufender Wasserhahn erst nach Stunden. + + Dasselbe Zeitfeld wie von/bis darüber, nur als Dauer gelesen. Dass + es keine Uhrzeit meint, sagt der Text ringsum ("erst nach … am + Stück"); die Zeile über dem Rahmen schreibt es beim Tippen aus + ("erst nach 3,5 Std."). -->
Auslösen erst nach - - Min. am Stück + + am Stück
diff --git a/doku/automatiken.md b/doku/automatiken.md index 1b2cfbf..5369e6e 100644 --- a/doku/automatiken.md +++ b/doku/automatiken.md @@ -170,7 +170,7 @@ sonst steht in der Übersicht etwas anderes als im Editor. | `next_day` | Der Rahmen gilt für **morgen** (Vorabend-Form) | Uhrzeit und Fenster bleiben bei heute | | `window_from`/`window_to` | Zeitfenster; `von > bis` heißt über Mitternacht | | | `lockout_secs` | Sperrzeit nach einem Lauf (0 / 60 / 900) | | -| `hold_secs` | Haltezeit: so lange muss die Bedingung **ununterbrochen** erfüllt sein (0 = sofort, frei in Minuten bis 24 Std.) | Zählt im Speicher des Runners — ein Neustart fängt die Zeit von vorn an | +| `hold_secs` | Haltezeit: so lange muss die Bedingung **ununterbrochen** erfüllt sein (0 = sofort, frei als Stunden:Minuten bis 23:59) | Zählt im Speicher des Runners — ein Neustart fängt die Zeit von vorn an | | `once_per_day` | höchstens ein Lauf je Kalendertag | | | `force_once` | am Ende des Fensters notfalls doch ausführen | greift nur, wenn im Fenster gar nichts lief | @@ -448,5 +448,5 @@ räumt der Runner selbst weg. | … verstehen, warum etwas lief | `automation_log`, dann die Zeitleiste des Tages (→ [zeitleiste.md](zeitleiste.md)) | | … das Nachholfenster ändern | `catchup_minutes` in `config.ini` des Runners | | … eine weitere Stufe für die Sperre | `lockoutChoices()` in `restricted/automations.php` — eine Zeile, der Rest zieht nach | -| … die Grenzen der Haltezeit ändern | `haltezeitPruefen()` in `restricted/automations.php` **und** `max` am Feld `holdMin` | +| … die Grenzen der Haltezeit ändern | `haltezeitPruefen()` in `restricted/automations.php` **und** `haltezeitAusUhr()` im Editor | | … auf Dauerzustände reagieren (Wasser läuft, Tür steht offen) | Haltezeit im Rahmen, dazu eine Aktion des Geräts „Benachrichtigungen“ (→ [benachrichtigungen.md](benachrichtigungen.md)) | diff --git a/js/solar/autoActionFuncs.js b/js/solar/autoActionFuncs.js index d9505a9..31ffc85 100644 --- a/js/solar/autoActionFuncs.js +++ b/js/solar/autoActionFuncs.js @@ -1136,10 +1136,36 @@ function rahmenKurzText() { return teile.join(" · "); } -/** Wie haltezeitKurz() in automations.php: Minuten bis eine Stunde, dann Stunden. */ +/** + * Haltezeit und Zeitfeld ineinander umrechnen. + * + * Das Feld ist ein gewoehnliches , sein Wert also "03:30". + * Gemeint ist keine Uhrzeit, sondern eine Dauer - deshalb hier zwei eigene + * Funktionen und nicht die Behandlung von window_from/window_to, die den Text + * unveraendert durchreichen. + */ +function haltezeitAlsUhr(sekunden) { + const min = Math.round(sekunden / 60); + return String(Math.floor(min / 60)).padStart(2, "0") + ":" + + String(min % 60).padStart(2, "0"); +} + +/** Leer oder unsinnig ist 0; die Obergrenze ist 23:59, siehe haltezeitPruefen(). */ +function haltezeitAusUhr(text) { + const teile = String(text || "").split(":"); + const sek = ((Number(teile[0]) || 0) * 60 + (Number(teile[1]) || 0)) * 60; + return Math.min(Math.max(sek, 0), 86340); +} + +/** Wie haltezeitKurz() in automations.php - dort steht, warum nicht gerundet wird. */ function haltezeitKurz(sekunden) { - if (sekunden < 3600) return Math.floor(sekunden / 60) + " Min."; - return (sekunden / 3600).toFixed(1).replace(/[.,]0$/, "").replace(".", ",") + " Std."; + const minuten = Math.floor(sekunden / 60); + if (minuten < 60) return minuten + " Min."; + const stunden = Math.floor(minuten / 60); + const rest = minuten % 60; + if (rest === 0) return stunden + " Std."; + if (rest === 30) return stunden + ",5 Std."; + return stunden + " Std. " + rest + " Min."; } function rahmenIstVorgabe() { @@ -1181,7 +1207,7 @@ function fuelleFormular() { const sperre = document.getElementById("lockoutSecs"); optionListe(sperre, autoLockouts.map(o => ({ value: o.value, text: o.label })), autoModel.lockout_secs); - document.getElementById("holdMin").value = autoModel.hold_secs / 60; + document.getElementById("holdZeit").value = haltezeitAlsUhr(autoModel.hold_secs); document.getElementById("autoName").value = autoModel.name; // Kennt die Liste die Etage nicht, bleibt eine Auswahlliste sonst leer // stehen und schickt beim Speichern "" mit. @@ -1216,10 +1242,7 @@ function leseFormular() { autoModel.once_per_day = document.getElementById("oncePerDay").checked; autoModel.next_day = document.getElementById("nextDay").checked; autoModel.lockout_secs = Number(document.getElementById("lockoutSecs").value); - // Minuten im Feld, Sekunden im Modell - und nichts Unmoegliches: ein - // leeres Feld ist 0, ein Tag ist die Obergrenze (siehe haltezeitPruefen()). - const halten = Math.round(Number(document.getElementById("holdMin").value) || 0); - autoModel.hold_secs = Math.min(Math.max(halten, 0), 1440) * 60; + autoModel.hold_secs = haltezeitAusUhr(document.getElementById("holdZeit").value); } /** @@ -1227,15 +1250,15 @@ function leseFormular() { * Ohne das stuende dort "rund um die Uhr", waehrend darunter 08:45 steht. */ function rahmenFelderVerdrahten() { - ["tSpanFrom", "tSpanTo", "lockoutSecs", "holdMin", + ["tSpanFrom", "tSpanTo", "lockoutSecs", "holdZeit", "runOnce", "oncePerDay", "nextDay"].forEach(id => { const feld = document.getElementById(id); if (feld) feld.addEventListener("change", () => { leseFormular(); renderRahmen(); }); }); - // Bei der Haltezeit schon beim Tippen: aus "210" wird in der Kopfzeile - // "erst nach 3,5 Std." - genau dafuer gibt man die Zahl ein. "change" - // allein kaeme erst beim Verlassen des Feldes. - document.getElementById("holdMin") + // Bei der Haltezeit schon beim Tippen: aus "03:30" wird in der Kopfzeile + // "erst nach 3,5 Std.". "change" allein kaeme erst beim Verlassen des + // Feldes, und ein Zeitfeld verlaesst man ungern, um nachzusehen. + document.getElementById("holdZeit") .addEventListener("input", () => { leseFormular(); renderRahmen(); }); // Zugeklappt steht in der Kopfzeile, was gilt; aufgeklappt stehen dort die diff --git a/restricted/automations.php b/restricted/automations.php index a179b5e..5d37372 100644 --- a/restricted/automations.php +++ b/restricted/automations.php @@ -232,11 +232,12 @@ function lockoutChoices() * Wasserhahn erst nach Stunden. Eine Stufenliste traefe immer nur die Haelfte * der Faelle. * - * Grenzen gibt es trotzdem. Unter null ist keine Zeit; oberhalb eines Tages + * Grenzen gibt es trotzdem. Unter null ist keine Zeit; oberhalb von 23:59 * waere es keine Haltezeit mehr, sondern ein Dauerzustand, den man besser - * anders abfragt - und das Zeitfenster schneidet sie ohnehin ab. Gerechnet - * wird in ganzen Minuten, weil der Editor Minuten anbietet und Sekunden hier - * nichts gewinnen: die Messwerte kommen viel seltener. + * anders abfragt - und das Zeitfenster schneidet sie ohnehin ab. Die Obergrenze + * ist genau das, was ein Zeitfeld hergibt. Gerechnet wird in ganzen Minuten, + * weil der Editor Stunden und Minuten anbietet und Sekunden hier nichts + * gewinnen: die Messwerte kommen viel seltener. */ function haltezeitPruefen($sekunden) { @@ -244,26 +245,36 @@ function haltezeitPruefen($sekunden) if ($sekunden < 0) { $sekunden = 0; } - if ($sekunden > 86400) { - $sekunden = 86400; + if ($sekunden > 86340) { // 23:59, mehr kann das Zeitfeld nicht + $sekunden = 86340; } return intdiv($sekunden, 60) * 60; } /** - * Eine Haltezeit in Worten - "45 Min.", "1 Std.", "3,5 Std." + * Eine Haltezeit in Worten - "45 Min.", "1 Std.", "3,5 Std.", "23 Std. 59 Min." * * Minuten bis eine Stunde, darueber Stunden: "210 Min." muss man umrechnen, - * "3,5 Std." nicht. Die Nachkommastelle faellt weg, wenn sie null ist. + * "3,5 Std." nicht. Halbe Stunden bekommen ihr Komma, alles andere Krumme die + * Minuten ausgeschrieben - gerundet wird nicht. Aus 23:59 wurde sonst + * "24 Std.", und eine Haltezeit, die laenger aussieht als sie ist, waere + * genau die falsche Auskunft. */ function haltezeitKurz($sekunden) { - $sekunden = intval($sekunden); - if ($sekunden < 3600) { - return intdiv($sekunden, 60) . " Min."; + $minuten = intdiv(intval($sekunden), 60); + if ($minuten < 60) { + return $minuten . " Min."; } - $zahl = number_format($sekunden / 3600, 1, ",", ""); - return rtrim(rtrim($zahl, "0"), ",") . " Std."; + $stunden = intdiv($minuten, 60); + $rest = $minuten % 60; + if ($rest === 0) { + return $stunden . " Std."; + } + if ($rest === 30) { + return $stunden . ",5 Std."; + } + return $stunden . " Std. " . $rest . " Min."; } /**