Jalousien waehrend der Fahrt nachfuehren
actor_states.current_value schrieb bisher nur der AutoAction-Runner fort, und der fragt die Tahoma-Box alle fuenf Minuten ab (poll_tahoma). Nach einem Fahrbefehl stand im Raum-Modal deshalb bis zu fuenf Minuten lang der Stand von vor der Fahrt. Das Modal verfolgt die Jalousie jetzt selbst: alle zwei Sekunden fragt es ueber ajax/room.php?action=jalousie genau dieses eine Geraet, zieht die beiden Regler und das Lamellenbild nach und hoert auf, sobald die Box keinen Fahrbefehl mehr meldet. Der gelesene Stand landet dabei gleich in actor_states, damit auch das naechste Oeffnen und der Automatik-Editor ihn haben. Wer gerade selbst am Schieber zieht, behaelt ihn. Drei Dinge mussten dafuer aus dem Weg: - Die Sitzung. helper.php startet sie und schliesst sie nie, PHP sperrt ihre Datei bis zum Ende der Anfrage. Ein "Zu" wartet ueber eine Minute auf das Ende der Fahrt - solange stand jede weitere Anfrage desselben Browsers still. ajax/room.php gibt sie jetzt frei, sobald checkLogin() durch ist; danach wird $_SESSION nur noch gelesen. - Drei Abfragen je Warterunde. warteAufJalousie() holte MovingState, Neigung und Position einzeln, obwohl eine Abfrage die ganze Liste liefert. Jetzt eine. - Kein Ort, an dem der frische Stand haengenbleibt. Dafuer tahomaZustaende(), tahomaZustaendeSchreiben() und tahomaAktorUrl(). Wahrheitswerte werden dabei als "True"/"False" geschrieben - so macht es der Runner mit str(), und zwei Schreibweisen fuer denselben Zustand waeren schlimmer als eine schraege. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+129
-8
@@ -279,8 +279,18 @@ function tahomaKommando($deviceUrl, $name, $parameter)
|
||||
}
|
||||
}
|
||||
|
||||
/** Einen Zustandswert eines Tahoma-Geraets lesen, null wenn unbekannt. */
|
||||
function tahomaZustand($deviceUrl, $feld)
|
||||
/**
|
||||
* Alle Zustaende eines Tahoma-Geraets in einem Zug lesen.
|
||||
*
|
||||
* Die Box liefert auf eine Abfrage ohnehin die ganze Liste. Drei einzelne
|
||||
* Aufrufe fuer drei Felder waren dreimal derselbe Weg dorthin - und
|
||||
* ausgerechnet in der Warteschleife, die alle zwei Sekunden nachsieht.
|
||||
*
|
||||
* Rueckgabe: Feldname => Wert, oder null, wenn die Box nicht antwortet. Ein
|
||||
* leeres Array waere hier falsch: es hiesse "Geraet kennt keine Zustaende"
|
||||
* und liesse eine Warteschleife durchlaufen, statt sie warten zu lassen.
|
||||
*/
|
||||
function tahomaZustaende($deviceUrl)
|
||||
{
|
||||
$ch = curl_init("https://gateway-" . $GLOBALS["tahoma_PIN"]
|
||||
. ":8443/enduser-mobile-web/1/enduserAPI/setup/devices/"
|
||||
@@ -295,12 +305,87 @@ function tahomaZustand($deviceUrl, $feld)
|
||||
if (!is_array($antwort)) {
|
||||
return null;
|
||||
}
|
||||
$werte = [];
|
||||
foreach ($antwort as $zustand) {
|
||||
if (($zustand["name"] ?? "") === $feld) {
|
||||
return $zustand["value"];
|
||||
if (isset($zustand["name"])) {
|
||||
$werte[$zustand["name"]] = $zustand["value"] ?? null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return $werte;
|
||||
}
|
||||
|
||||
/** Einen Zustandswert eines Tahoma-Geraets lesen, null wenn unbekannt. */
|
||||
function tahomaZustand($deviceUrl, $feld)
|
||||
{
|
||||
$zustaende = tahomaZustaende($deviceUrl);
|
||||
return $zustaende === null ? null : ($zustaende[$feld] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Einen Zustandswert so in Text fassen, wie der Runner es tut.
|
||||
*
|
||||
* In actor_states.current_value schrieb bisher nur der Runner, und der macht
|
||||
* str() daraus - aus einem Wahrheitswert wird dort "True" bzw. "False", nicht
|
||||
* "1" und "". Das sieht aus PHP heraus schraeg aus, ist aber wichtig: sonst
|
||||
* stuenden fuer denselben Zustand zwei Schreibweisen in der Tabelle, je
|
||||
* nachdem wer zuletzt geschrieben hat. istAn() in roomControls.php kennt
|
||||
* beide, eine Bedingung im Automatik-Editor vergleicht aber stur.
|
||||
*/
|
||||
function tahomaWertText($wert)
|
||||
{
|
||||
if (is_bool($wert)) {
|
||||
return $wert ? "True" : "False";
|
||||
}
|
||||
return strval($wert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Die frisch gelesenen Zustaende eines Tahoma-Geraets in actor_states
|
||||
* festhalten.
|
||||
*
|
||||
* Sonst schreibt dort nur der Runner, und der fragt die Box alle fuenf
|
||||
* Minuten ab (poll_tahoma in seiner config.ini) - nach einem Fahrbefehl
|
||||
* zeigte jedes Modal bis dahin den Stand von vor der Fahrt. Die Werte liegen
|
||||
* hier ohnehin schon vor, weil die Warteschleife sie gelesen hat.
|
||||
*
|
||||
* Geschrieben wird nur, was sich geaendert hat. Der Runner haelt einen
|
||||
* eigenen Merkzettel darueber, was er zuletzt geschrieben hat; er wird
|
||||
* unsere Zeile beim naechsten Poll hoechstens einmal ueberfluessig
|
||||
* ueberschreiben, denn er liest dieselbe Box.
|
||||
*
|
||||
* Rueckgabe: wie viele Zeilen geaendert wurden.
|
||||
*/
|
||||
function tahomaZustaendeSchreiben($deviceUrl, $zustaende)
|
||||
{
|
||||
if (!is_array($zustaende) || !$zustaende) {
|
||||
return 0;
|
||||
}
|
||||
$db = commandDb();
|
||||
$stmt = $db->prepare("SELECT s.id, s.url, s.current_value FROM actor_states s
|
||||
JOIN actors a ON a.id = s.actor_id
|
||||
WHERE a.url = ? AND s.url IS NOT NULL AND s.url <> ''");
|
||||
$stmt->bind_param("s", $deviceUrl);
|
||||
$stmt->execute();
|
||||
$zeilen = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
|
||||
$stmt->close();
|
||||
|
||||
$geaendert = 0;
|
||||
$schreib = $db->prepare("UPDATE actor_states SET current_value = ? WHERE id = ?");
|
||||
foreach ($zeilen as $zeile) {
|
||||
if (!array_key_exists($zeile["url"], $zustaende)) {
|
||||
continue;
|
||||
}
|
||||
$text = tahomaWertText($zustaende[$zeile["url"]]);
|
||||
if (strval($zeile["current_value"]) === $text) {
|
||||
continue;
|
||||
}
|
||||
$id = intval($zeile["id"]);
|
||||
$schreib->bind_param("si", $text, $id);
|
||||
$schreib->execute();
|
||||
$geaendert++;
|
||||
}
|
||||
$schreib->close();
|
||||
return $geaendert;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,9 +411,13 @@ function warteAufJalousie($deviceUrl, $neigungZiel, $schliessungZiel = null)
|
||||
$gestartet = false;
|
||||
while (time() - $start < JALOUSIE_WARTE_SEKUNDEN) {
|
||||
sleep(2);
|
||||
$faehrt = tahomaZustand($deviceUrl, "core:MovingState");
|
||||
$neigung = tahomaZustand($deviceUrl, "core:SlateOrientationState");
|
||||
$schliessung = tahomaZustand($deviceUrl, "core:ClosureState");
|
||||
$zustaende = tahomaZustaende($deviceUrl);
|
||||
if ($zustaende === null) {
|
||||
continue;
|
||||
}
|
||||
$faehrt = $zustaende["core:MovingState"] ?? null;
|
||||
$neigung = $zustaende["core:SlateOrientationState"] ?? null;
|
||||
$schliessung = $zustaende["core:ClosureState"] ?? null;
|
||||
if ($faehrt === true) {
|
||||
$gestartet = true;
|
||||
continue;
|
||||
@@ -340,12 +429,44 @@ function warteAufJalousie($deviceUrl, $neigungZiel, $schliessungZiel = null)
|
||||
|| ($schliessung !== null && intval($schliessung) === $schliessungZiel);
|
||||
if ($neigungOk && $schliessungOk
|
||||
&& ($gestartet || time() - $start >= JALOUSIE_VORLAUF_SEKUNDEN)) {
|
||||
// Die Fahrt ist zu Ende und die Werte sind gerade gelesen - der
|
||||
// guenstigste Moment, sie festzuhalten.
|
||||
tahomaZustaendeSchreiben($deviceUrl, $zustaende);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Geraete-URL eines Aktors, null wenn es ihn nicht gibt oder er nicht an
|
||||
* der Tahoma-Box haengt.
|
||||
*
|
||||
* Die Pruefung auf die Box-Kennung ist dieselbe wie im Runner: am Schema
|
||||
* laesst sich ein Tahoma-Geraet nicht erkennen, dieselbe Box liefert io://
|
||||
* fuer die Jalousien, rts:// fuer die Dachfenster und internal:// fuer die
|
||||
* Alarmanlage. Ohne sie wuerde eine Anfrage mit der Nummer einer Shelly die
|
||||
* Box nach einer URL fragen, die sie nicht kennt.
|
||||
*/
|
||||
function tahomaAktorUrl($actorId)
|
||||
{
|
||||
$pin = strval($GLOBALS["tahoma_PIN"] ?? "");
|
||||
if ($pin === "") {
|
||||
return null;
|
||||
}
|
||||
$db = commandDb();
|
||||
$stmt = $db->prepare("SELECT url FROM actors WHERE id = ?");
|
||||
$id = intval($actorId);
|
||||
$stmt->bind_param("i", $id);
|
||||
$stmt->execute();
|
||||
$zeile = $stmt->get_result()->fetch_assoc();
|
||||
$stmt->close();
|
||||
if (!$zeile || strpos(strval($zeile["url"]), "://" . $pin . "/") === false) {
|
||||
return null;
|
||||
}
|
||||
return $zeile["url"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hat das Geraet ein Kommando, das Position und Neigung zusammen setzt?
|
||||
* Nur solche Geraete sind Jalousien mit der Kugelschreiber-Mechanik.
|
||||
|
||||
Reference in New Issue
Block a user