/ * mqtt Name des Raums im MQTT-Baum: Raumtemp///... * id Kürzel in den SVG-Element-IDs: _w0_, __heater * x, y Position der Kachel im SVG (viewBox 400x300) - fehlt bei Räumen * ohne Kachel * werte Was auf der Kachel steht: bis zu drei Messwerte, jeder mit * topic, optional pfad (Schlüssel in einer JSON-Nachricht), * einheit und stellen (Nachkommastellen). Fehlt der Eintrag, sind * es die drei Thermostatwerte - Soll, Ist, Feuchte - wie bisher. * Eine leere Liste heisst: kein Messwert, die Kachel trägt nur * ihren Namen und öffnet den Raum. * * Ein Raum ohne x/y ist trotzdem ein Raum: Geräte lassen sich ihm zuordnen * (siehe die Spalte actors.room und den Zuordnungsdialog in der Karte * "Automatismen"), er erscheint nur nicht als Kachel im Grundriss. Derzeit * hat jeder Raum eine Kachel; die Unterscheidung bleibt, weil ein neuer Raum * zuerst als Zeile ohne Position entsteht und erst dann seinen Platz im * Grundriss bekommt. * * Wo eine Kachel hingehört, misst tools/kachelpositionen.php aus: Grundriss * mit Raster, Geisterkachel am Zeiger, fertige Zeile zum Abschreiben. x/y * ist die linke obere Ecke der 24 x 19 grossen Kachel, nicht ihre Mitte. */ // Reihenfolge im Menü und in der Anzeige; OG ist die Standardetage. // // AG ist das Außengelände - eine Etage ohne Grundriss. Was draußen hängt, // stand vorher als Pseudo-Raum "aussen" in automations.php und war damit ein // einziger Topf: Carport, Pergola, Garage und die Wechselrichter alle // nebeneinander. Als Etage bekommt jeder davon einen Raum, und die // Geräteauswahl im Automatik-Editor gruppiert danach wie überall sonst. $floors = ["OG", "EG", "UG", "AG"]; // Ausgeschriebene Namen für Beschriftungen, wo Platz ist. Das Kürzel steht in // URLs (?floor=AG), in SVG-Element-Ids (AG_Info) und im MQTT-Baum - dort will // man weder Umlaute noch Länge. $floorLabels = [ "OG" => "Obergeschoss", "EG" => "Erdgeschoss", "UG" => "Untergeschoss", "AG" => "Außengelände", ]; $rooms = [ ["floor" => "OG", "mqtt" => "Wohnzimmer", "id" => "wozi", "x" => 180, "y" => 140], ["floor" => "OG", "mqtt" => "KiZi", "id" => "kizi", "x" => 130, "y" => 80], ["floor" => "OG", "mqtt" => "Schlafzimmer", "id" => "schlafen", "x" => 235, "y" => 70], ["floor" => "OG", "mqtt" => "Bad", "id" => "bad", "x" => 260, "y" => 120], ["floor" => "OG", "mqtt" => "Buero", "id" => "buero", "x" => 265, "y" => 175], // Kein Thermostat, und noch kein Gerät zugeordnet - die Kachel trägt // vorerst nur ihren Namen. ["floor" => "OG", "mqtt" => "Kueche", "id" => "kueche", "x" => 122, "y" => 138, "werte" => []], ["floor" => "OG", "mqtt" => "Technik", "id" => "technik", "x" => 173, "y" => 67, "werte" => []], ["floor" => "EG", "mqtt" => "Wohnzimmer", "id" => "wozi", "x" => 185, "y" => 150], ["floor" => "EG", "mqtt" => "Florian", "id" => "kizi", "x" => 130, "y" => 90], ["floor" => "EG", "mqtt" => "Schlafen", "id" => "schlafen", "x" => 235, "y" => 80], ["floor" => "EG", "mqtt" => "Bad", "id" => "bad", "x" => 253, "y" => 130], ["floor" => "EG", "mqtt" => "Magdalena", "id" => "buero", "x" => 258, "y" => 180], ["floor" => "EG", "mqtt" => "Kueche", "id" => "kueche", "x" => 126, "y" => 146, "werte" => []], // Der Shelly-Zähler des EG meldet seine Werte als JSON in einer einzigen // Nachricht; "pfad" greift den Schlüssel daraus heraus. ["floor" => "EG", "mqtt" => "Technik", "id" => "technik", "x" => 172, "y" => 78, "werte" => [ ["topic" => "Power_EG/status/em:0", "pfad" => "total_act_power", "einheit" => "W", "stellen" => 0, "gross" => true], ]], ["floor" => "UG", "mqtt" => "Buero", "id" => "buero", "x" => 140, "y" => 140], ["floor" => "UG", "mqtt" => "Bad", "id" => "bad", "x" => 210, "y" => 80], ["floor" => "UG", "mqtt" => "Kueche", "id" => "kueche", "x" => 190, "y" => 195], ["floor" => "UG", "mqtt" => "Technik", "id" => "technik", "x" => 238, "y" => 93, "werte" => [ ["topic" => "Power_UG/status/em:0", "pfad" => "total_act_power", "einheit" => "W", "stellen" => 0, "gross" => true], ["topic" => "wasser/main/value", "einheit" => "m³", "stellen" => 1], ]], // Außengelände: noch ohne x/y, es gibt ja keinen Lageplan, auf den eine // Kachel zeigen könnte. Zuordnen und Automatiken anlegen geht trotzdem - // dafür zählt allein, dass der Raum hier steht. Kommt der Lageplan, sind // es zwei Zahlen je Zeile, gemessen mit tools/kachelpositionen.php. // // Die Namen stammen von den Geräten selbst: die Hoymiles heißen seit jeher // "Carport 1-6" und "Veranda OG2-4", das Sonnensegel sitzt an der Pergola. // Zwei Carports, einer je Wohnpartei - deshalb dieselben Kuerzel wie die // Etagen. Die Wattpilot der EG-Partei steht dagegen in der Garage, siehe // restricted/config.php; am Carport OG haengt der go-e Charger. ["floor" => "AG", "mqtt" => "Carport EG", "id" => "carport_eg", "werte" => []], ["floor" => "AG", "mqtt" => "Carport OG", "id" => "carport_og", "werte" => []], // Veranda und Terrasse gibt es zweimal, je Wohnpartei eine. In der // Draufsicht laege das obere Paar genau auf dem unteren - deshalb die // Schraegsicht, siehe restricted/aussenplan.php. ["floor" => "AG", "mqtt" => "Veranda EG", "id" => "veranda_eg", "werte" => []], ["floor" => "AG", "mqtt" => "Veranda OG", "id" => "veranda_og", "werte" => []], ["floor" => "AG", "mqtt" => "Terrasse EG", "id" => "terrasse_eg", "werte" => []], ["floor" => "AG", "mqtt" => "Terrasse OG", "id" => "terrasse_og", "werte" => []], ["floor" => "AG", "mqtt" => "Pergola", "id" => "pergola", "werte" => []], ["floor" => "AG", "mqtt" => "Garage", "id" => "garage", "werte" => []], // Der Garten ist kein Bauteil wie die anderen, aber ein Ort: hier haengen // der Regensensor und die beiden Ventilsteuerungen. ["floor" => "AG", "mqtt" => "Garten", "id" => "garten", "werte" => []], ]; /** * Räume einer Etage, die eine Kachel im Grundriss haben. * * Alles, was zeichnet oder aktualisiert, geht hierüber - ein Raum ohne * Position hätte keine Stelle im SVG und keine Elemente, die sich füllen * liessen. */ function roomsOnFloor($floor) { return array_values(array_filter($GLOBALS["rooms"], function ($room) use ($floor) { return $room["floor"] == $floor && isset($room["x"]); })); } /** Alle Räume, auch die ohne Kachel - für die Geräte-Zuordnung. */ function allRooms() { return $GLOBALS["rooms"]; } /** Ausgeschriebener Name einer Etage; unbekannte bleiben ihr Kürzel. */ function floorLabel($floor) { return $GLOBALS["floorLabels"][$floor] ?? $floor; } /** * Etagen mit Grundriss - die, die im Menü und im SVG auftauchen. * * Das Außengelände ist eine Etage ohne Bild: seine Räume haben keine Kachel, * und ein Menüpunkt dorthin führte auf eine leere Zeichenfläche. Sobald der * erste AG-Raum ein x/y bekommt, erscheint die Etage von selbst auch dort - * es gibt keine zweite Liste, die man nachziehen müsste. * * Für die Zuordnung und die Automatiken zählt dagegen $floors: dort ist das * Außengelände von Anfang an dabei. */ function floorsWithPlan() { return array_values(array_filter($GLOBALS["floors"], function ($floor) { return count(roomsOnFloor($floor)) > 0; })); } /** Nur die Räume mit Kachel, für die Aktualisierungsschleife im Browser. */ function roomsWithTile() { return array_values(array_map("mitWerten", array_filter($GLOBALS["rooms"], function ($room) { return isset($room["x"]); }))); } /** * Die Messwerte einer Kachel, fertig ausgeschrieben. * * Ohne eigene Angabe sind es die drei Thermostatwerte, die dort schon immer * standen: Solltemperatur klein darüber, Isttemperatur gross, Feuchte klein * darunter. Nur diese Räume bekommen auch die Symbole für "heizt" und * "Pufferbetrieb" - anderswo gibt es nichts zu heizen. */ function mitWerten($room) { if (isset($room["werte"])) { $room["heizung"] = false; $room["werte"] = array_slice($room["werte"], 0, 3); return $room; } $zweig = "Raumtemp/" . $room["floor"] . "/" . $room["mqtt"] . "/"; $room["heizung"] = true; $room["werte"] = [ ["topic" => $zweig . "Set Temp[degC]", "einheit" => "°C", "stellen" => 0], ["topic" => $zweig . "Temp[degC]", "einheit" => "°C", "gross" => true], ["topic" => $zweig . "rHum[%]", "einheit" => "%rF"], ]; return $room; } /** * Was der Browser beim Broker anmelden muss, damit die Kacheln laufen. * * Nicht die einzelnen Topics, sondern ihre Zweige: aus vierzig Anmeldungen * für Raumtemp werden so vier insgesamt. Der Zweig bringt ausserdem mit, * was die Kachel nebenbei braucht - "Heating" und "mode" stehen in keiner * Werteliste, das Heizsymbol lebt aber davon. */ function tileTopics() { $zweige = []; foreach (roomsWithTile() as $room) { foreach ($room["werte"] as $wert) { $zweige[explode("/", $wert["topic"])[0] . "/#"] = true; } } return array_keys($zweige); }