Jalousien: Zu heisst zweifach schwenken, Versand laeuft im Hintergrund
Die Kugelschreiber-Mechanik betrifft jedes Kommando, nicht nur
setOrientation, und sie betrifft auch das Schliessen: ein "Zu" faehrt die
Jalousie zwar herunter, die Lamellen bleiben aber bei etwa 30 % offen
stehen. Dicht wird sie erst durch das zweifache Schwenken.
Die Regel lautet jetzt einheitlich: derselbe Befehl zweimal - erst mit
Neigung 0, dann warten, bis die Fahrt steht, dann mit dem gewuenschten Wert.
Die Position bleibt dabei erhalten, die Jalousie faehrt also nur einmal.
Zu -> [100,0] warten [100,100]
Neigung 20 -> direkt, unter der Schwelle
Neigung 80 -> [0] warten [80]
Position 40 Neigung 50 -> [40,0] warten [40,50]
"Zu" wird dabei nur umgeschrieben, wenn das Geraet Position und Neigung
zusammen setzen kann - der einfache Rollladen "Terasse" hat keine Lamellen
und bekommt weiter das rohe down.
Gewartet wird auf zwei Auskuenfte zusammen, weil einzeln keine traegt:
core:MovingState trug die lange Fahrt (gemessen 61 s), wird bei kurzen
Neigungsfahrten aber nie gesetzt; die Zustandswerte sind die Wahrheit,
zeigen direkt nach dem Kommando aber noch den alten Stand. Fertig heisst:
nichts faehrt mehr, die Ziele stimmen, und es wurde entweder ein "faehrt"
gesehen oder der Vorlauf von acht Sekunden ist um.
Und weil ein "Zu" damit ueber eine Minute dauert, schickt der Runner nicht
mehr selbst: der neue Versand nimmt die Kommandos entgegen und arbeitet sie
in eigenen Faeden ab - je Geraet der Reihe nach, ueber Geraete hinweg
nebeneinander. Sonst haette eine einzige Jalousie die ganze Auswertung fuer
eine Minute angehalten: keine Zeit-Ausloeser, keine Messwerte, und mehrere
Rollladen in einer Automatik haetten sich aufaddiert. Die Datenbank bleibt
dabei im Hauptfaden - die Faeden melden nur ihr Ergebnis zurueck, eine
pymysql-Verbindung ist nicht fuer mehrere Faeden gedacht.
Nachgemessen: Einreihen kehrt sofort zurueck, zwei Kommandos an dasselbe
Geraet laufen nacheinander (6 s, dann 12 s), drei an verschiedene Geraete
gleichzeitig, Fehler kommen zurueck, und die Schleife lief in 20 Sekunden
20 Takte durch.
Die Bedienung im Modal wartet weiterhin - dort sitzt ein Mensch vor einem
Fortschritt und klickt einmal. ajax/room.php hebt dafuer die Zeitgrenze auf
180 Sekunden an, wie es ajax/tahoma.php an derselben Stelle auch tut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+108
-30
@@ -44,14 +44,29 @@ const MQTT_PORT = 1883;
|
||||
*/
|
||||
const NEIGUNG_DIREKT_MAX = 30;
|
||||
|
||||
/** So heisst der Neigungsparameter im Geraetemodell. */
|
||||
/** So heissen die beiden Parameter einer Jalousie im Geraetemodell. */
|
||||
const NEIGUNG_PARAMETER = "Neigung";
|
||||
const POSITION_PARAMETER = "Position";
|
||||
|
||||
/**
|
||||
* So lange wird hoechstens auf das Ende einer Neigungsfahrt gewartet.
|
||||
* Gemessen braucht eine Jalousie von 100 % auf 0 % gut fuenfzehn Sekunden.
|
||||
* So lange wird hoechstens auf das Ende einer Fahrt gewartet.
|
||||
*
|
||||
* Gemessen: eine Neigung von 100 % auf 0 % dauert gut fuenfzehn Sekunden,
|
||||
* eine volle Fahrt von oben nach unten rund sechzig. Die Grenze ist die
|
||||
* Notbremse, nicht die uebliche Dauer.
|
||||
*/
|
||||
const NEIGUNG_WARTE_SEKUNDEN = 25;
|
||||
const JALOUSIE_WARTE_SEKUNDEN = 120;
|
||||
|
||||
/**
|
||||
* So lange gilt ein "faehrt nicht" direkt nach dem Absenden als noch nicht
|
||||
* aussagekraeftig.
|
||||
*
|
||||
* Die Box meldet core:MovingState traege: kurz nach einem Kommando steht
|
||||
* dort noch der alte Wert. Ohne diesen Vorlauf haelt die Warteschleife die
|
||||
* Fahrt fuer beendet, bevor sie begonnen hat - und das naechste Kommando
|
||||
* schneidet sie ab.
|
||||
*/
|
||||
const JALOUSIE_VORLAUF_SEKUNDEN = 8;
|
||||
|
||||
/** Verbindung zur Geraetedatenbank. */
|
||||
function commandDb()
|
||||
@@ -289,59 +304,122 @@ function tahomaZustand($deviceUrl, $feld)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wartet, bis die Neigung den Zielwert erreicht hat.
|
||||
* Wartet, bis die Jalousie ihre Fahrt beendet hat und die Zielwerte zeigt.
|
||||
*
|
||||
* Auf core:MovingState ist bei Neigungsfahrten kein Verlass - gemessen hat
|
||||
* die Box waehrend einer solchen Fahrt kein einziges Mal "faehrt" gemeldet.
|
||||
* Der Zustandswert selbst ist die verlaessliche Auskunft.
|
||||
* Zwei Auskuenfte zusammen, weil einzeln keine traegt:
|
||||
*
|
||||
* core:MovingState taugt fuer die lange Fahrt hoch und runter, wird
|
||||
* bei kurzen Neigungsfahrten aber nie gesetzt.
|
||||
* die Zustandswerte sind die eigentliche Wahrheit, brauchen aber
|
||||
* einen Vorlauf, weil sie kurz nach dem Kommando
|
||||
* noch den alten Stand zeigen.
|
||||
*
|
||||
* Fertig ist die Fahrt, wenn nichts mehr faehrt, die Ziele erreicht sind und
|
||||
* entweder ein "faehrt" gesehen wurde oder der Vorlauf um ist.
|
||||
*
|
||||
* $schliessungZiel darf null sein, wenn das Kommando die Position nicht
|
||||
* anfasst.
|
||||
*/
|
||||
function warteAufNeigung($deviceUrl, $ziel)
|
||||
function warteAufJalousie($deviceUrl, $neigungZiel, $schliessungZiel = null)
|
||||
{
|
||||
for ($i = 0; $i < NEIGUNG_WARTE_SEKUNDEN; $i++) {
|
||||
sleep(1);
|
||||
$wert = tahomaZustand($deviceUrl, "core:SlateOrientationState");
|
||||
$start = time();
|
||||
$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");
|
||||
if ($faehrt === true) {
|
||||
$gestartet = true;
|
||||
continue;
|
||||
}
|
||||
// null heisst "nicht gelesen". intval() daraus waere 0 - und damit
|
||||
// ausgerechnet beim Ziel 0 ein falsches Erfolgssignal, das die
|
||||
// Warteschleife sofort beendet.
|
||||
if ($wert !== null && intval($wert) === $ziel) {
|
||||
// ausgerechnet beim Ziel 0 ein falsches Erfolgssignal.
|
||||
$neigungOk = $neigung !== null && intval($neigung) === $neigungZiel;
|
||||
$schliessungOk = $schliessungZiel === null
|
||||
|| ($schliessung !== null && intval($schliessung) === $schliessungZiel);
|
||||
if ($neigungOk && $schliessungOk
|
||||
&& ($gestartet || time() - $start >= JALOUSIE_VORLAUF_SEKUNDEN)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hat das Geraet ein Kommando, das Position und Neigung zusammen setzt?
|
||||
* Nur solche Geraete sind Jalousien mit der Kugelschreiber-Mechanik.
|
||||
*/
|
||||
function jalousieKombiKommando($actorUrl)
|
||||
{
|
||||
$db = commandDb();
|
||||
$stmt = $db->prepare("SELECT c.command_url FROM actor_commands c
|
||||
JOIN actors a ON a.id = c.actor_id
|
||||
WHERE a.url = ? AND c.command_url = 'setClosureAndOrientation'");
|
||||
$stmt->bind_param("s", $actorUrl);
|
||||
$stmt->execute();
|
||||
$treffer = $stmt->get_result()->fetch_assoc();
|
||||
$stmt->close();
|
||||
return $treffer ? $treffer["command_url"] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tahoma: exec/apply an die Box - dieselbe Form wie in ajax/tahoma.php, nur
|
||||
* ohne dessen Sonderbehandlung fuer "faehrt gerade".
|
||||
*/
|
||||
function sendeTahoma($cmd, $werte, $probe)
|
||||
{
|
||||
$befehl = $cmd["command_url"];
|
||||
$parameter = [];
|
||||
$neigungsziel = null;
|
||||
foreach (parameterWerte($cmd, $werte) as $p) {
|
||||
$neigungIndex = null;
|
||||
$positionIndex = null;
|
||||
foreach (parameterWerte($cmd, $werte) as $i => $p) {
|
||||
// Die Box erwartet Zahlen als Zahlen, Text als Text.
|
||||
$parameter[] = is_numeric($p["wert"]) ? $p["wert"] + 0 : $p["wert"];
|
||||
if ($p["name"] === NEIGUNG_PARAMETER && is_numeric($p["wert"])) {
|
||||
$neigungsziel = $p["wert"] + 0;
|
||||
if ($p["name"] === NEIGUNG_PARAMETER) {
|
||||
$neigungIndex = $i;
|
||||
} elseif ($p["name"] === POSITION_PARAMETER) {
|
||||
$positionIndex = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// Kugelschreiber-Mechanik: ueber NEIGUNG_DIREKT_MAX hinaus rastet die
|
||||
// Mechanik nur um, wenn sie vorher einmal auf 0 % war. Der Umweg gehoert
|
||||
// hierher und nicht in die Bedienung - sonst muesste ihn jeder kennen,
|
||||
// der eine Jalousie anspricht.
|
||||
$umweg = ($neigungsziel !== null && $neigungsziel > NEIGUNG_DIREKT_MAX);
|
||||
// "Zu" allein macht diese Jalousien nicht dicht: sie faehrt herunter, die
|
||||
// Lamellen bleiben durch die Mechanik aber bei etwa 30 % offen stehen.
|
||||
// Gemeint ist "ganz unten, Lamellen geschlossen" - also dasselbe wie
|
||||
// Position 100 mit Neigung 100, und damit ein Fall fuer die Regel unten.
|
||||
if ($befehl === "down" && jalousieKombiKommando($cmd["actor_url"])) {
|
||||
$befehl = "setClosureAndOrientation";
|
||||
$parameter = [100, 100];
|
||||
$positionIndex = 0;
|
||||
$neigungIndex = 1;
|
||||
}
|
||||
|
||||
// Kugelschreiber-Mechanik: ueber NEIGUNG_DIREKT_MAX hinaus rastet sie nur
|
||||
// um, wenn sie vorher einmal auf 0 % war. Geschickt wird deshalb derselbe
|
||||
// Befehl zweimal - erst mit Neigung 0, dann mit dem gewuenschten Wert.
|
||||
// Die Position bleibt dabei stehen, die Jalousie faehrt also nur einmal.
|
||||
$umweg = $neigungIndex !== null
|
||||
&& is_numeric($parameter[$neigungIndex])
|
||||
&& $parameter[$neigungIndex] > NEIGUNG_DIREKT_MAX;
|
||||
|
||||
$vorstufe = $parameter;
|
||||
if ($umweg) {
|
||||
$vorstufe[$neigungIndex] = 0;
|
||||
}
|
||||
|
||||
if ($probe) {
|
||||
$text = "Tahoma: " . $cmd["command_url"] . " " . json_encode($parameter);
|
||||
return $umweg ? $text . " (mit Umweg über Neigung 0)" : $text;
|
||||
$text = "Tahoma: " . $befehl . " " . json_encode($parameter);
|
||||
return $umweg
|
||||
? $text . " (zuerst " . json_encode($vorstufe) . ", dann warten)"
|
||||
: $text;
|
||||
}
|
||||
|
||||
if ($umweg) {
|
||||
tahomaKommando($cmd["actor_url"], "setOrientation", [0]);
|
||||
warteAufNeigung($cmd["actor_url"], 0);
|
||||
tahomaKommando($cmd["actor_url"], $befehl, $vorstufe);
|
||||
warteAufJalousie($cmd["actor_url"], 0,
|
||||
$positionIndex === null ? null : intval($parameter[$positionIndex]));
|
||||
}
|
||||
tahomaKommando($cmd["actor_url"], $cmd["command_url"], $parameter);
|
||||
tahomaKommando($cmd["actor_url"], $befehl, $parameter);
|
||||
return $cmd["actor_name"] . ": " . $cmd["command_name"]
|
||||
. ($umweg ? " (über 0 % geneigt)" : "");
|
||||
. ($umweg ? " (über Neigung 0 gefahren)" : "");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user