["Beschattung", "", "#60afbf"],
"heizung" => ["Heizung", "bi-thermometer-half", "#e5624f"],
"licht" => ["Licht", "bi-lightbulb", "#f7c000"],
"schalter" => ["Schalten", "bi-toggle-on", "#6cbe58"],
"sonstiges" => ["Geräte", "bi-sliders", "#9aa6ad"],
"messwerte" => ["Messwerte", "bi-speedometer2", "#4b9fd6"],
];
}
/**
* Die Geraetegruppen als Reiter-Kacheln.
*
* Jede Kachel traegt unter ihrem Namen den Zustand der Gruppe ("2 von 3 zu",
* "25,7 °C", "1 an") - den setzt js/solar/raumfenster.js, weil er sich
* waehrend des Bedienens aendert. Bei nur einer Gruppe bleibt die Leiste
* trotzdem stehen: sie ist hier auch die Zusammenfassung.
*
* $fertig sind Gruppen, deren Inhalt der Aufrufer schon gebaut hat und die
* nicht aus einer Geraeteliste entstehen - die Heizung ist so eine: ein
* Regler fuer den Raum, nicht eine Karte je Geraet.
*/
function zeichneGruppen($gruppen, $fertig = [])
{
$vorhanden = [];
foreach (raumGruppenTitel() as $form => $titel) {
if (!empty($gruppen[$form]) || isset($fertig[$form])) {
$vorhanden[$form] = $titel;
}
}
if (!$vorhanden) {
return "";
}
$leiste = "
";
}
/** Ein "wahr"-artiger Wert - die Geraete melden mal True, mal 1, mal "on". */
function istAn($wert)
{
if ($wert === null) {
return false;
}
return in_array(strtolower(trim(strval($wert))), ["1", "true", "on", "an", "ein", "yes"], true);
}
/**
* Nebensaechliche Kommandos in ein Mehr-Menue, damit sie nicht stoeren.
*
* Nur Kommandos ohne Parameter: ein Menuepunkt bietet nichts zum Einstellen,
* ein "Position+Neigung" von hier aus wuerde ohne Werte losgeschickt. Was
* Parameter braucht, hat oben seine Bedienung.
*/
function mehrMenue($cmds)
{
$cmds = array_values(array_filter($cmds, function ($c) { return !count($c["params"]); }));
if (!$cmds) {
return "";
}
$html = "
";
}
// ===========================================================================
// Die Bedienformen
// ===========================================================================
/** Zahl aus einem Zustand, oder "" wenn es keinen gibt. */
function zustandsZahl($d, $namen)
{
$wert = zustandsWert($d, $namen);
return is_numeric($wert) ? strval(intval($wert)) : "";
}
/**
* "Alle im Raum": ein Knopf, viele Geraete. Das JavaScript geht die Karten
* durch und schickt jedem das passende eigene Kommando - "Sichtschutz" nur
* denen, die Hoehe und Neigung zusammen setzen koennen.
*/
function alleImRaum($geraete)
{
$mitMy = false;
$mitNeigung = false;
foreach ($geraete as $d) {
$mitMy = $mitMy || kommandoMitUrl($d, ["my"]);
$mitNeigung = $mitNeigung || kombiKommando($d);
}
return "
";
}
// Presets, Effekte und andere Listen. Wenige Eintraege stehen als Chips
// da; lange Listen (WLED hat ueber 180 Effekte) bekommen einen Knopf mit
// dem aktuellen Eintrag, der eine durchsuchbare Liste aufklappt. Die
// native Auswahlliste zeichnet der Browser hell auf hell und passt nicht
// in das dunkle Fenster. Welcher Eintrag gerade gilt, liest
// js/solar/raumfenster.js bei WLED live aus (room.php?action=wled);
// data-feld ist der Parametername, "effect" oder "preset".
foreach ($listen as $c) {
$p = $c["params"][0];
$kopf = "
";
}
/** Alles, was nur an und aus kennt: eine Kachel zum Antippen. */
function zeichneSchalter($d)
{
$schalter = schaltKommandos($d);
$an = istAn(zustandsWert($d, ["An", "ison", "on", "state", "Status"]));
return "";
}
/**
* Geraete, die nur melden: ein Wertegitter statt einer Textwurst.
*
* Ein Stromzaehler hat sechzehn Werte. Alle sechzehn hinzuschreiben ist
* genauso unbrauchbar wie acht davon abzuschneiden - die ersten sechs
* stehen da, der Rest ist einen Klick entfernt.
*/
function zeichneMesswerte($d)
{
$html = karteAuf($d, htmlspecialchars($d["type"]));
$states = nachWichtigkeit($d["states"]);
$sichtbar = array_slice($states, 0, 6);
$weitere = array_slice($states, 6);
$html .= "
";
}
return $html . karteZu();
}
/**
* Messwerte so ordnen, dass die sechs sichtbaren die richtigen sind.
*
* Die Reihenfolge in der Datenbank ist die des Geraetesuchlaufs: beim
* Wasserzaehler standen MAC-Adresse, Firmware und freier Speicher vorn, der
* Verbrauch hinter "12 weitere Werte". Vorne gehoert hin, was gemessen wird -
* ein Wert mit Einheit -, hinten, was ueber das Geraet selbst Auskunft gibt.
*/
function nachWichtigkeit($states)
{
$diagnose = ["mac", "hostname", "fwversion", "uptime", "freemem", "rssi",
"error", "status", "ip", "ssid", "version"];
$rang = function ($s) use ($diagnose) {
$leer = $s["value"] === null || $s["value"] === "";
$technisch = in_array(strtolower($s["name"]), $diagnose, true);
return ($technisch ? 4 : 0) + ($leer ? 2 : 0) + ($s["unit"] ? 0 : 1);
};
usort($states, function ($a, $b) use ($rang) { return $rang($a) - $rang($b); });
return $states;
}
function wertKachel($s)
{
$wert = strval($s["value"]);
if ($wert === "") {
$wert = "–";
}
// Messwerte kommen mit voller Rechengenauigkeit aus dem Geraet; auf einer
// Kachel liest niemand 231.10000000000002.
if (is_numeric($wert) && strpos($wert, ".") !== false) {
$wert = rtrim(rtrim(number_format(floatval($wert), 2, ",", ""), "0"), ",");
}
return "
";
}
/** Was in keine Form passt: Kommandos so, wie sie in der Datenbank stehen. */
function zeichneSonstiges($d)
{
$html = karteAuf($d, htmlspecialchars($d["type"]));
$knoepfe = array_values(array_filter($d["commands"], function ($c) { return !count($c["params"]); }));
if ($knoepfe) {
$html .= "