diff --git a/ajax/room.php b/ajax/room.php index 49b82ac..36c6ee7 100644 --- a/ajax/room.php +++ b/ajax/room.php @@ -84,18 +84,18 @@ $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. +// Alles im Raum, sortiert nach Bedienform. Das Thermostat selbst wird nicht +// als Karte gezeichnet: es wird zum Schieberegler im Heizungs-Reiter und +// braucht daneben keine zweite Bedienung - "Solltemperatur" stand sonst +// zweimal im Modal. +// +// Ob es einen Heizungs-Reiter gibt, entscheidet genau das: haengt in diesem +// Raum ein Thermostat? Frueher stand hier "hat der Raum eine Kachel" - das +// stimmte, solange nur Raeume mit Thermostat eine bekamen. Seit auch Kueche +// und Technik eine haben, bekamen sie einen Heizungsregler fuer eine +// Heizung, die es dort nicht gibt. $katalog = deviceCatalog(); +$hatThermostat = false; $gruppen = []; foreach ($katalog as $d) { if ($d["room"] !== $raumKey) { @@ -103,6 +103,7 @@ foreach ($katalog as $d) { } $form = bedienform($d); if ($form === "heizung") { + $hatThermostat = true; continue; } $gruppen[$form][] = $d; diff --git a/js/solar/homeMQTT.js b/js/solar/homeMQTT.js index 58c2cf5..6f6549a 100644 --- a/js/solar/homeMQTT.js +++ b/js/solar/homeMQTT.js @@ -13,7 +13,10 @@ const homeMQTT = { client.on("message", messageReceived); client.on("connect", function () { - client.subscribe("Raumtemp/#"); + // Welche Zweige gebraucht werden, sagt die Raumtabelle: seit eine + // Kachel jeden Messwert zeigen kann, reicht Raumtemp allein nicht + // mehr. homeTopics kommt aus restricted/rooms.php. + homeTopics.forEach(function (topic) { client.subscribe(topic); }); }); client.on("error", function (error) { //alert("MQTT Error: " + error); @@ -51,25 +54,67 @@ const homeSVG = { fillElementArray: function () { }, + /** + * Eine Nachricht aus dem Baum holen. mqttData ist nach den Teilen des + * Topics verschachtelt, siehe setNestedProp() weiter oben. + */ + ausTopic: function (mqttData, topic) { + return topic.split("/").reduce(function (zweig, teil) { + return zweig && zweig[teil]; + }, mqttData); + }, + + /** + * Einen Kachelwert lesen und hinschreiben. + * + * "pfad" ist gesetzt, wenn das Geraet mehrere Werte in einer einzigen + * JSON-Nachricht schickt - die beiden Shelly-Zaehler tun das. "stellen" + * schneidet Nachkommastellen ab; ohne Angabe bleibt der Text so, wie das + * Geraet ihn meldet. + */ + kachelWert: function (mqttData, wert) { + const roh = homeSVG.ausTopic(mqttData, wert.topic); + if (typeof roh === "undefined") return null; + let text = String(roh); + if (wert.pfad) { + try { + const daten = JSON.parse(text); + if (!(wert.pfad in daten)) return null; + text = String(daten[wert.pfad]); + } catch (fehler) { + return null; // noch keine vollstaendige Nachricht + } + } + if (typeof wert.stellen === "number" && text !== "" && !isNaN(Number(text))) { + text = Number(text).toFixed(wert.stellen); + } + // Schmales Leerzeichen zwischen Zahl und Einheit, wie es sich gehoert. + return wert.einheit ? text + "\u2009" + wert.einheit : text; + }, + updateValuesMQTT: function (mqttData) { - // homeRooms liefert restricted/rooms.php (in home.php eingebettet). - // Jeder Raum bekommt die gleiche Behandlung - Raeume kommen dort dazu, - // nicht hier. + // homeRooms liefert restricted/rooms.php (in home.php eingebettet), + // mitsamt den Werten, die auf der Kachel stehen sollen. Jeder Raum + // bekommt die gleiche Behandlung - Raeume und ihre Werte kommen dort + // dazu, nicht hier. homeRooms.forEach(function (room) { - const values = mqttData["Raumtemp"]?.[room.floor]?.[room.mqtt]; - if (!values) return; // Topic noch nicht empfangen const el = (part) => document.getElementById(room.floor + "_" + part); + room.werte.forEach(function (wert, i) { + const text = homeSVG.kachelWert(mqttData, wert); + const feld = el("w" + i + "_" + room.id); + if (text !== null && feld) feld.innerHTML = text; + }); + + // Heizsymbol und Pufferbetrieb gibt es nur, wo ein Thermostat + // haengt - anderswo sind die Elemente gar nicht gezeichnet. + if (!room.heizung) return; + const values = mqttData["Raumtemp"]?.[room.floor]?.[room.mqtt]; + if (!values) return; if (typeof (values["Heating"]) != "undefined") el(room.id + "_heater").setAttribute("display", values["Heating"] == "false" ? "none" : ""); if (typeof (values["mode"]) != "undefined") el(room.id + "_buffer").setAttribute("display", values["mode"] == "Overheating" ? "" : "none"); - if (typeof (values["Set Temp[degC]"]) != "undefined") - el("pres_" + room.id).innerHTML = Math.floor(values["Set Temp[degC]"]) + "\u2009\u00b0C"; - if (typeof (values["Temp[degC]"]) != "undefined") - el("tmp_" + room.id).innerHTML = values["Temp[degC]"] + "\u2009\u00b0C"; - if (typeof (values["rHum[%]"]) != "undefined") - el("hum_" + room.id).innerHTML = values["rHum[%]"] + "\u2009%rF"; }); } diff --git a/restricted/home.php b/restricted/home.php index 1e8250f..a424707 100644 --- a/restricted/home.php +++ b/restricted/home.php @@ -107,15 +107,36 @@ > - + + [12], 2 => [9, 16], 3 => [5, 11.5, 16.5]]; + $y = $zeilen[count($room["werte"])] ?? []; +?> ,)" onclick="openHeaterSettings('_');" cursor="pointer"> + _heater" href="#heater" display="none" /> _buffer" href="#buffer" display="none" /> + - " y="5" x="12" text-anchor="middle">---- hPa - " x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C - " x="12" dy="1.2em" text-anchor="middle">-- %rF + + + + + $wert): ?> + + " x="12" y="" + text-anchor="middle">– + @@ -198,8 +219,11 @@