Die Heizung stand ueber den Tabs und war in jedem Raum sichtbar, auch wenn man wegen der Rollladen gekommen war. Sie ist jetzt eine Gruppe wie die anderen - nur baut sie sich nicht aus einer Geraeteliste, sondern ist ein Regler fuer den Raum. zeichneGruppen() nimmt dafuer fertige Inhalte entgegen. Bei einem Raum mit nur einem Thermostat bleibt die Leiste weg, dort sieht es aus wie vorher. Aus den Pillen sind Reiter geworden - sie sehen jetzt aus wie das, was sie sind, und nicht wie eine Knopfreihe. Position und Neigung standen um 0,35 rem versetzt: die Regel fuer gestapelte Regler (Helligkeit ueber Farbe) griff auch auf die zweite Spalte, die aber danebensteht. Sie gilt jetzt nur noch fuer Regler, die keine Spalte sind - nachgemessen stehen beide Bahnen auf 181/104. Das Fensterbild ist von "so breit wie moeglich" auf 5 rem zurueckgenommen; der uebrige Platz verteilt sich auf die Zwischenraeume, statt das Bild breitzuziehen. Zwischen ihm und den Bedienelementen liegt jetzt Luft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
143 lines
5.9 KiB
PHP
143 lines
5.9 KiB
PHP
<?php
|
||
/**
|
||
* Raum-Modal: alles, was in einem Raum haengt, auf einer Seite.
|
||
*
|
||
* Loest das frühere Thermostat-Modal ab. Der Grundriss zeigt Raeume, also
|
||
* sollte ein Klick darauf den Raum oeffnen und nicht nur seine Heizung - die
|
||
* Rollladen im selben Zimmer waren bisher gar nicht erreichbar.
|
||
*
|
||
* Welche Geraete zu einem Raum gehoeren, sagt die Spalte actors.room (siehe
|
||
* den Zuordnungsdialog in der Karte "Automatismen").
|
||
*
|
||
* GET ?room=EG_Bad Inhalt des Modals
|
||
* POST ?action=command {"command_id": N, "params": {...}} - ein Kommando
|
||
* POST ?action=temp {"room": "EG_Bad", "temp": 21} - Solltemperatur
|
||
*/
|
||
|
||
// Ein "Zu" an einer Jalousie faehrt herunter, wartet und neigt danach - das
|
||
// dauert in der Summe ueber eine Minute. Die Vorgabe von PHP reicht dafuer
|
||
// nicht; ajax/tahoma.php macht es an derselben Stelle genauso.
|
||
set_time_limit(180);
|
||
|
||
require_once("../helper.php");
|
||
require_once("../restricted/automations.php");
|
||
require_once("../restricted/commands.php");
|
||
require_once("../restricted/roomControls.php");
|
||
require_once("./phpMQTT.php");
|
||
|
||
if (!checkLogin()) {
|
||
http_response_code(403);
|
||
exit;
|
||
}
|
||
|
||
function raumAntwort($data, $code = 200)
|
||
{
|
||
http_response_code($code);
|
||
header("Content-Type: application/json; charset=utf-8");
|
||
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||
exit;
|
||
}
|
||
|
||
// --- Schaltende Aufrufe ---------------------------------------------------
|
||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||
$body = json_decode(file_get_contents("php://input"), true);
|
||
if (!is_array($body)) {
|
||
raumAntwort(["error" => "Konnte die Anfrage nicht lesen."], 400);
|
||
}
|
||
try {
|
||
if (($_GET["action"] ?? "") === "command") {
|
||
$text = executeCommand(intval($body["command_id"] ?? 0),
|
||
is_array($body["params"] ?? null) ? $body["params"] : [],
|
||
!empty($body["probe"]));
|
||
raumAntwort(["ok" => $text]);
|
||
}
|
||
if (($_GET["action"] ?? "") === "temp") {
|
||
// Bewusst derselbe Weg wie im alten Thermostat-Modal: das Topic
|
||
// Raumtemp/<Etage>/<Raum>/changeSetTemp.
|
||
$raum = preg_replace('/[^A-Za-z0-9_]/', '', strval($body["room"] ?? ""));
|
||
$temp = intval($body["temp"] ?? 0);
|
||
if ($temp < 10 || $temp > 30) {
|
||
raumAntwort(["error" => "Temperatur außerhalb 10–30 °C."], 400);
|
||
}
|
||
$mqtt = new Bluerhinos\phpMQTT(MQTT_BROKER, MQTT_PORT, "RoomTempSetter_" . getmypid());
|
||
if (!$mqtt->connect(true, null, "", "")) {
|
||
raumAntwort(["error" => "Keine Verbindung zum MQTT-Broker."], 500);
|
||
}
|
||
$mqtt->publish("Raumtemp/" . str_replace("_", "/", $raum) . "/changeSetTemp",
|
||
strval($temp), 0, false);
|
||
$mqtt->close();
|
||
raumAntwort(["ok" => "Solltemperatur " . $temp . " °C"]);
|
||
}
|
||
raumAntwort(["error" => "Unbekannte Aktion."], 400);
|
||
} catch (InvalidArgumentException $e) {
|
||
raumAntwort(["error" => $e->getMessage()], 400);
|
||
} catch (Throwable $e) {
|
||
raumAntwort(["error" => $e->getMessage()], 500);
|
||
}
|
||
}
|
||
|
||
|
||
// --- Inhalt des Modals ----------------------------------------------------
|
||
$schluessel = preg_replace('/[^A-Za-z0-9_]/', '', strval($_GET["room"] ?? ""));
|
||
$teile = explode("_", $schluessel, 2);
|
||
$etage = $teile[0] ?? "";
|
||
$name = $teile[1] ?? "";
|
||
$raumKey = $etage . "/" . $name;
|
||
|
||
// Hat der Raum ein Thermostat? Nur dann gibt es etwas zu heizen.
|
||
$hatThermostat = false;
|
||
foreach (allRooms() as $raum) {
|
||
if ($raum["floor"] === $etage && $raum["mqtt"] === $name) {
|
||
$hatThermostat = isset($raum["x"]); // Kachel = Thermostat vorhanden
|
||
}
|
||
}
|
||
|
||
// Alles im Raum, sortiert nach Bedienform. Das Thermostat selbst faellt
|
||
// heraus: es wird oben zum Schieberegler und braucht daneben keine zweite
|
||
// Bedienung - "Solltemperatur" stand vorher zweimal im Modal.
|
||
$katalog = deviceCatalog();
|
||
$gruppen = [];
|
||
foreach ($katalog as $d) {
|
||
if ($d["room"] !== $raumKey) {
|
||
continue;
|
||
}
|
||
$form = bedienform($d);
|
||
if ($form === "heizung") {
|
||
continue;
|
||
}
|
||
$gruppen[$form][] = $d;
|
||
}
|
||
|
||
// Die Heizung ist eine Gruppe wie die anderen, nur baut sie sich nicht aus
|
||
// einer Geraeteliste: ein Regler fuer den Raum statt einer Karte je Geraet.
|
||
$fertig = [];
|
||
if ($hatThermostat) {
|
||
$karte = "<div class='card mb-2'><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;
|
||
}
|
||
|
||
echo "<div class='p-1' id='roomView' data-room='" . htmlspecialchars($schluessel, ENT_QUOTES) . "'>";
|
||
|
||
if (!$gruppen && !$fertig) {
|
||
echo "<p class='text-body-secondary mb-0'>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>";
|