diff --git a/js/solar/homeMQTT.js b/js/solar/homeMQTT.js index 548e80e..e9ea5ec 100644 --- a/js/solar/homeMQTT.js +++ b/js/solar/homeMQTT.js @@ -513,16 +513,17 @@ function switchFloor(floor){ function raumKommando(cmdId, params, element) { const karte = element.closest(".raum-geraet") || element; karte.classList.add("raum-warte"); - // Die Verfolgung beginnt sofort, nicht erst mit der Antwort: ein "Zu" - // faehrt herunter, wartet und neigt danach - der Aufruf kommt also erst - // zurueck, wenn die Jalousie schon steht. Beides nebeneinander geht, - // seit ajax/room.php die Sitzung freigibt. - jalousieVerfolgen(karte); - raumRequest("command", { command_id: cmdId, params: params }) - .then(antwort => { - karte.classList.remove("raum-warte"); - raumMeldung(antwort); - }); + // Die Verfolgung laeuft neben dem Auftrag her, nicht nach ihm: ein "Zu" + // faehrt herunter, wartet und neigt danach - die Antwort kaeme also erst, + // wenn die Jalousie schon steht. Beides nebeneinander geht, seit + // ajax/room.php die Sitzung freigibt. Der Auftrag geht mit, weil nur er + // weiss, wann das Manoever zu Ende ist. + const auftrag = raumRequest("command", { command_id: cmdId, params: params }); + jalousieVerfolgen(karte, auftrag); + auftrag.then(antwort => { + karte.classList.remove("raum-warte"); + raumMeldung(antwort); + }); } // Takt und Grenzen der Verfolgung. Dieselben Zahlen wie die Konstanten @@ -533,16 +534,33 @@ function switchFloor(floor){ const JALOUSIE_VORLAUF_MS = 8000; const JALOUSIE_MAX_MS = 120000; + // Wie lange nach dem Ende des Auftrags noch nachgesehen wird. Eine + // Neigungsfahrt setzt core:MovingState nie (siehe warteAufJalousie() in + // restricted/commands.php), dauert aber gemessen bis zu fuenfzehn Sekunden + // von Anschlag zu Anschlag - ohne diesen Nachlauf stuende der Wert von + // vor dem letzten Schwenk in der Anzeige. + const JALOUSIE_NACHLAUF_MS = 14000; + /** - * Eine Jalousie waehrend ihrer Fahrt nachfuehren. + * Nach einem Fahrbefehl abwarten, bis die Jalousie steht, und dann ihren + * wirklichen Stand zeigen. * * actor_states schreibt sonst nur der Runner fort, und der fragt die * Tahoma-Box alle fuenf Minuten ab - so lange zeigte das Modal nach einem * Fahrbefehl den Stand von davor. Hier wird genau dieses eine Geraet * gefragt; ajax/room.php haelt den frischen Wert gleich in der Tabelle * fest, damit auch das naechste Oeffnen und der Automatik-Editor ihn haben. + * + * Waehrend der Fahrt wird bewusst nichts angezeigt. An der Anlage + * gemessen: die Hoehe (core:ClosureState) steht die ganze Fahrt ueber auf + * dem Wert von vor dem Kommando und springt erst am Ende um - wer sie + * anzeigte, holte den Regler vom eingestellten Ziel auf den alten Stand + * zurueck, nur um ihn zwanzig Sekunden spaeter wieder vorzuschieben. Die + * Neigung meldet zwar Zwischenwerte, aber ausgerechnet die der + * Kugelschreiber-Mechanik: bei "Neigung 80" liefe der Regler 62 -> 28 -> + * 38 -> 79, ueber einen Umweg, den niemand angefordert hat. */ - function jalousieVerfolgen(karte) { + function jalousieVerfolgen(karte, auftrag) { if (!karte || !karte.querySelector(".raum-jalousie")) return; const actor = Number(karte.dataset.actor); if (!actor) return; @@ -555,6 +573,16 @@ function switchFloor(floor){ const beginn = Date.now(); let gefahren = false; + // Solange der Auftrag laeuft, ist nichts entschieden: die + // Kugelschreiber-Mechanik schickt zwei Befehle mit einer Wartezeit + // dazwischen, und zwischen ihnen steht die Jalousie still. Wer da + // aufhoert, schreibt die Zwischenstellung fest - gemessen "Neigung 0", + // wo 62 gemeint war. + let ruheAb = Infinity; + Promise.resolve(auftrag).then( + function () { ruheAb = Date.now() + JALOUSIE_NACHLAUF_MS; }, + function () { ruheAb = Date.now(); } + ); function aufhoeren() { delete karte.dataset.jalousieLaeuft; @@ -563,14 +591,24 @@ function switchFloor(floor){ function runde(letzte) { raumRequest("jalousie", { actor: actor }).then(stand => { + // Ein Fehler soll auffallen. Ohne die Meldung endet die Schleife + // still, und die Anzeige bleibt einfach stehen - nicht zu + // unterscheiden von "die Verfolgung gibt es gar nicht". + if (stand && stand.error) raumMeldung(stand); // Modal zu, Box stumm, Geraet unbekannt - in jedem Fall aufhoeren // statt zwei Minuten lang ins Leere zu fragen. if (!stand || stand.error || !document.body.contains(karte)) { aufhoeren(); return; } - jalousieAnzeigen(karte, stand); - if (stand.faehrt) gefahren = true; + if (stand.faehrt) { + gefahren = true; + } else if (Date.now() >= ruheAb) { + // Erst wenn der Auftrag durch ist. Zwischen den beiden Befehlen der + // Kugelschreiber-Mechanik steht die Jalousie still und meldet + // "Neigung 0" - anzeigen hiesse, den Umweg vorzufuehren. + jalousieAnzeigen(karte, stand); + } if (letzte || Date.now() > Number(karte.dataset.jalousieBis)) { aufhoeren(); return; @@ -579,6 +617,7 @@ function switchFloor(floor){ // haben fahren sehen oder der Vorlauf um ist. Eine letzte Runde // danach holt den Wert, den die Box beim Anhalten setzt. const fertig = !stand.faehrt + && Date.now() >= ruheAb && (gefahren || Date.now() - beginn >= JALOUSIE_VORLAUF_MS); setTimeout(() => runde(fertig), JALOUSIE_TAKT_MS); }); @@ -586,7 +625,10 @@ function switchFloor(floor){ setTimeout(() => runde(false), JALOUSIE_TAKT_MS); } - /** Die gemeldete Stellung in die beiden Regler und das Bild uebernehmen. */ + /** + * Die gemeldete Stellung in die beiden Regler und das Bild uebernehmen. + * Aufgerufen nur im Stillstand, siehe jalousieVerfolgen(). + */ function jalousieAnzeigen(karte, stand) { [["position", stand.position], ["neigung", stand.neigung]].forEach(paar => { const wert = paar[1]; diff --git a/restricted/commands.php b/restricted/commands.php index 657de9f..e578a73 100644 --- a/restricted/commands.php +++ b/restricted/commands.php @@ -336,6 +336,13 @@ function tahomaWertText($wert) if (is_bool($wert)) { return $wert ? "True" : "False"; } + // Nicht jeder Zustand der Box ist eine Zahl oder ein Wort: manche sind + // Listen oder Objekte. Als Messwert taugt das nicht, und strval() darauf + // ist eine PHP-Warnung - die stuende dann mitten in der JSON-Antwort und + // machte sie unlesbar, ohne dass irgendwo ein Fehler auftaucht. + if (!is_scalar($wert)) { + return null; + } return strval($wert); } @@ -376,7 +383,7 @@ function tahomaZustaendeSchreiben($deviceUrl, $zustaende) continue; } $text = tahomaWertText($zustaende[$zeile["url"]]); - if (strval($zeile["current_value"]) === $text) { + if ($text === null || strval($zeile["current_value"]) === $text) { continue; } $id = intval($zeile["id"]);