Raum-Modal im neuen Stil: Reiter-Kacheln, Beschattung mit my, Heizring, Licht
- Beschattung: Auf/Stop/my/Zu, Hoehe und Lamellen in 25-%-Stufen, Ziehen im Fensterbild, neue Behang-Grafik ueber die ganze Kartenhoehe, Alle im Raum - my-Position: aktuellen Stand per setMemorized1Position/-Orientation in den Motor schreiben (room.php?action=my), gespeicherte Werte werden angezeigt - Heizung: Ring mit Ist-Temperatur und ziehbarem Soll-Punkt, -/+ und Schnellwahl - Licht: Birne als Schalter, Helligkeit, Farbfelder, Effekt/Preset eingeklappt - Logik aus homeMQTT.js nach js/solar/raumfenster.js; bindModalSlider entfaellt Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+82
-21
@@ -12,6 +12,9 @@
|
||||
* GET ?room=12 Inhalt des Modals, 12 = rooms.id
|
||||
* POST ?action=command {"command_id": N, "params": {...}} - ein Kommando
|
||||
* POST ?action=temp {"room": 12, "temp": 21} - Solltemperatur
|
||||
* POST ?action=jalousie {"actor": 5} - Stand einer Jalousie
|
||||
* POST ?action=my {"actor": 5} - aktuellen Stand als
|
||||
* my-Position speichern
|
||||
*
|
||||
* Frueher hiess der Raum "EG_Bad" und wurde am Unterstrich zerlegt. Das hielt
|
||||
* weder ein Leerzeichen im Namen aus (erst nachgeruestet) noch eine
|
||||
@@ -158,9 +161,53 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
? intval($zustaende[$feld]) : null;
|
||||
};
|
||||
raumAntwort([
|
||||
"faehrt" => ($zustaende["core:MovingState"] ?? null) === true,
|
||||
"position" => $zahl("core:ClosureState"),
|
||||
"neigung" => $zahl("core:SlateOrientationState"),
|
||||
"faehrt" => ($zustaende["core:MovingState"] ?? null) === true,
|
||||
"position" => $zahl("core:ClosureState"),
|
||||
"neigung" => $zahl("core:SlateOrientationState"),
|
||||
"myPosition" => $zahl("core:Memorized1PositionState"),
|
||||
"myNeigung" => $zahl("core:Memorized1OrientationState"),
|
||||
]);
|
||||
}
|
||||
// Den Stand, auf dem die Jalousie gerade steht, als my-Position in den
|
||||
// Motor schreiben. Die Box kennt dafuer setMemorized1Position und bei
|
||||
// Raffstores zusaetzlich setMemorized1Orientation; die Geraetesuche
|
||||
// uebernimmt beide nicht als Kommando, deshalb geht es hier direkt.
|
||||
// Gespeichert wird, was die Box meldet - nicht, was im Browser steht:
|
||||
// der koennte einer Fahrt hinterherhinken.
|
||||
if (($_GET["action"] ?? "") === "my") {
|
||||
$url = tahomaAktorUrl(intval($body["actor"] ?? 0));
|
||||
if ($url === null) {
|
||||
raumAntwort(["error" => "Kein Tahoma-Gerät mit dieser Nummer."], 404);
|
||||
}
|
||||
$vorher = tahomaZustaende($url);
|
||||
if ($vorher === null) {
|
||||
raumAntwort(["error" => "Tahoma-Box antwortet nicht."], 503);
|
||||
}
|
||||
if (($vorher["core:MovingState"] ?? null) === true) {
|
||||
raumAntwort(["error" => "Die Jalousie fährt noch – bitte warten, bis sie steht."], 409);
|
||||
}
|
||||
if (!isset($vorher["core:Memorized1PositionState"]) || !is_numeric($vorher["core:ClosureState"] ?? null)) {
|
||||
raumAntwort(["error" => "Dieses Gerät kann keine my-Position speichern."], 400);
|
||||
}
|
||||
$position = intval($vorher["core:ClosureState"]);
|
||||
$neigung = null;
|
||||
tahomaKommando($url, "setMemorized1Position", [$position]);
|
||||
$text = "my-Position " . $position . " %";
|
||||
if (isset($vorher["core:Memorized1OrientationState"]) && is_numeric($vorher["core:SlateOrientationState"] ?? null)) {
|
||||
$neigung = intval($vorher["core:SlateOrientationState"]);
|
||||
tahomaKommando($url, "setMemorized1Orientation", [$neigung]);
|
||||
$text .= ", Lamellen " . $neigung . " %";
|
||||
}
|
||||
// Die Box braucht einen Moment, bis sie den neuen Wert meldet.
|
||||
sleep(2);
|
||||
$nachher = tahomaZustaende($url);
|
||||
if ($nachher !== null) {
|
||||
tahomaZustaendeSchreiben($url, $nachher);
|
||||
}
|
||||
raumAntwort([
|
||||
"ok" => $text . " gespeichert",
|
||||
"myPosition" => $position,
|
||||
"myNeigung" => $neigung,
|
||||
]);
|
||||
}
|
||||
raumAntwort(["error" => "Unbekannte Aktion."], 400);
|
||||
@@ -210,34 +257,48 @@ foreach ($katalog as $d) {
|
||||
// einer Geraeteliste: ein Regler fuer den Raum statt einer Karte je Geraet.
|
||||
$fertig = [];
|
||||
if ($hatThermostat) {
|
||||
$karte = "<div class='card mb-2 raum-geraet'><div class='card-body py-2'>"
|
||||
. "<div class='d-flex justify-content-between align-items-baseline'>"
|
||||
. "<label class='form-label mb-0 small' for='modal-slider'>Solltemperatur</label>"
|
||||
. "<span id='modal-slider-label' class='fw-semibold text-nowrap ms-2' style='color:#297195'>–</span>"
|
||||
. "</div>"
|
||||
. "<input type='range' id='modal-slider' class='form-range range-color-track' min='10' max='30'>"
|
||||
// Der Ist-Zustand kommt live ueber MQTT, nicht aus der Datenbank -
|
||||
// der Browser hoert ohnehin schon auf Raumtemp/#, und ein Wert von
|
||||
// vorhin waere neben dem Regler nur irrefuehrend.
|
||||
. "<div class='d-flex flex-wrap gap-3 small text-body-secondary'>"
|
||||
. "<span><i class='bi bi-thermometer-half me-1'></i><span data-mqtt='Temp[degC]'>–</span> °C</span>"
|
||||
. "<span><i class='bi bi-droplet me-1'></i><span data-mqtt='rHum[%]'>–</span> %rF</span>"
|
||||
. "<span data-mqtt-heizung class='d-none'><i class='bi bi-fire text-danger me-1'></i>heizt</span>"
|
||||
. "</div></div></div>";
|
||||
$fertig["heizung"] = $karte;
|
||||
// Ring mit Ist-Temperatur und ziehbarem Soll-Punkt, daneben - und + und
|
||||
// die Schnellwahl. Alle Zahlen kommen live ueber MQTT (der Browser hoert
|
||||
// ohnehin auf den Thermostat-Zweig) und werden von js/solar/raumfenster.js
|
||||
// eingetragen. Das Thermostat nimmt ganze Grad von 10 bis 30 °C, siehe
|
||||
// action=temp.
|
||||
$fertig["heizung"] = "<div class='rf-heiz' data-rf-heiz-teil data-min='10' data-max='30'>"
|
||||
. "<div class='rf-ring'><svg viewBox='0 0 170 170'>"
|
||||
. "<defs><linearGradient id='rfHeizVerlauf' gradientUnits='userSpaceOnUse' gradientTransform='rotate(-135 85 85)' x1='15' y1='0' x2='155' y2='0'>"
|
||||
. "<stop offset='0' stop-color='#4b9fd6'/><stop offset='.55' stop-color='#e8a33a'/><stop offset='1' stop-color='#e5624f'/>"
|
||||
. "</linearGradient></defs>"
|
||||
. "<circle class='rf-ring-spur' cx='85' cy='85' r='70' transform='rotate(135 85 85)'/>"
|
||||
. "<circle class='rf-ring-ist' cx='85' cy='85' r='70' transform='rotate(135 85 85)'/>"
|
||||
. "<circle class='rf-ring-griff' cx='85' cy='85' r='70' transform='rotate(135 85 85)' data-rf-ringzug/>"
|
||||
. "<circle class='rf-ring-soll' cx='155' cy='85' r='10' data-rf-ringzug tabindex='0' role='slider'"
|
||||
. " aria-label='Solltemperatur' aria-valuemin='10' aria-valuemax='30'/></svg>"
|
||||
. "<div class='rf-ring-mitte'><small>im Raum</small><b data-rf-heiz='ist'>–</b><span data-rf-heiz='soll'>Soll –</span></div></div>"
|
||||
. "<div class='rf-heiz-rechts'><h3>Solltemperatur</h3>"
|
||||
. "<div class='rf-stepper'><button type='button' data-rf-schritt='-1' aria-label='1 Grad kälter'>−</button>"
|
||||
. "<output data-rf-heiz='wert'>–</output>"
|
||||
. "<button type='button' data-rf-schritt='1' aria-label='1 Grad wärmer'>+</button></div>"
|
||||
. "<div class='rf-chips'>"
|
||||
. "<button type='button' class='rf-chip' data-rf-soll='10' aria-pressed='false'>Minimum <span>10°</span></button>"
|
||||
. "<button type='button' class='rf-chip' data-rf-soll='17' aria-pressed='false'>Eco <span>17°</span></button>"
|
||||
. "<button type='button' class='rf-chip' data-rf-soll='21' aria-pressed='false'>Komfort <span>21°</span></button>"
|
||||
. "<button type='button' class='rf-chip' data-rf-soll='23' aria-pressed='false'>Warm <span>23°</span></button></div>"
|
||||
. "<div class='rf-hinweis' data-rf-heiz='hinweis' hidden><i class='bi bi-info-circle'></i><span></span></div>"
|
||||
. "<div class='rf-pillen'><span class='rf-pille'><i class='bi bi-droplet'></i><span data-rf-heiz='feuchte'>–</span></span>"
|
||||
. "<span class='rf-pille' data-rf-heiz='puffer' hidden><i class='bi bi-fire'></i>Pufferbetrieb</span></div>"
|
||||
. "</div></div>";
|
||||
}
|
||||
|
||||
// Der Thermostat-Zweig reist mit: das Modal fuellt Ist-Werte und Heizsymbol
|
||||
// aus dem laufenden MQTT-Strom und muss wissen, wo es nachsehen soll.
|
||||
echo "<div class='p-1' id='roomView' data-room='" . $raum["nr"] . "'"
|
||||
echo "<div class='rf' id='roomView' data-room='" . $raum["nr"] . "'"
|
||||
. " data-thermostat='" . htmlspecialchars((string)$raum["thermostat"], ENT_QUOTES) . "'>";
|
||||
|
||||
if (!$gruppen && !$fertig) {
|
||||
echo "<p class='text-body-secondary mb-0'>Diesem Raum ist noch nichts zugeordnet. "
|
||||
echo "<p class='rf-leer'>Diesem Raum ist noch nichts zugeordnet. "
|
||||
. "Das geht über das Haus-Symbol in der Karte „Automatismen“.</p>";
|
||||
}
|
||||
|
||||
echo zeichneGruppen($gruppen, $fertig);
|
||||
|
||||
echo "<div id='roomFeedback' class='small mt-2'></div>";
|
||||
echo "<div id='roomFeedback' class='rf-meldung' aria-live='polite'>Änderungen gelten sofort</div>";
|
||||
echo "</div>";
|
||||
|
||||
Reference in New Issue
Block a user