Files
Smart-Dashboard/ajax/settings.php
T
adminandClaude Opus 5 cd398bc800 Kachelsymbole: jedes Bootstrap-Icon statt einer Handvoll
Fuer die Symbole vor den Zahlen standen drei Codepunkte von Hand in
rooms.php, und die Maske bot genau diese drei an. Jedes weitere Symbol waere
eine Codeaenderung gewesen.

Die Codepunkte stehen aber schon im Haus: css/bootstrap-icons.min.css fuehrt
sie unter .bi-<name>::before - dieselbe Quelle, aus der auch der Browser
liest. bootstrapIcons() liest sie von dort (2078 Stueck, einmal je Anfrage),
kachelIcon() schlaegt darin nach. Damit ist jedes Symbol moeglich, und ein
Versionswechsel der Icons zieht von selbst mit.

In der Maske steht deshalb kein Auswahlfeld mehr, sondern der Name mit einer
Vorschau davor - "moisture" sagt nichts, das Symbol daneben schon. Die
Vorschlagsliste beginnt mit gut dreissig ueblichen Symbolen unter deutscher
Beschriftung (Temperatur, Feuchte, Leistung, Wallbox, Regen ...), danach folgt
der ganze Rest alphabetisch. Ein Name, den es nicht gibt, zeigt sofort ein
rotes Fragezeichen und wird beim Speichern mit Begruendung abgelehnt.

In der eingeklappten Kurzfassung einer Kachel steht das Symbol jetzt mit -
es ist das schnellste Erkennungszeichen dafuer, welcher der drei Werte
gemeint ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 23:24:14 +02:00

136 lines
5.0 KiB
PHP

<?php
/**
* Endpunkt der Einstellungsseite.
*
* GET ?action=list&reihe=strom Zeitraeume einer Preistabelle
* POST ?action=save {"reihe": "strom", "zeilen": [ ... ]}
* GET ?action=kacheln Anzeigewerte aller Home-Kacheln
* POST ?action=kacheln-save {"floor": "OG", "room": "bad",
* "werte": [ ... ] oder null}
* GET ?action=geraete Geraete mit Raum, Verwendung und Alter
* POST ?action=geraete-raeume {"rooms": {"12": "OG/Bad", ...}}
* POST ?action=geraet-loeschen {"id": 12}
*
* Ein reiner Verteiler: geprueft und geschrieben wird in
* restricted/costs.php bzw. restricted/kacheln.php, damit Maske und Endpunkt
* dieselbe Wahrheit ueber einen Zeitraum oder eine Kachel haben.
*/
require_once("../helper.php");
require_once("../restricted/costs.php");
require_once("../restricted/kacheln.php");
require_once("../restricted/automations.php");
if (!checkLogin()) {
http_response_code(403);
exit;
}
function jsonAntwort($data, $code = 200)
{
http_response_code($code);
header("Content-Type: application/json; charset=utf-8");
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit;
}
$action = $_GET["action"] ?? "list";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$body = json_decode(file_get_contents("php://input"), true);
if (!is_array($body)) {
jsonAntwort(["error" => "Konnte die Anfrage nicht lesen."], 400);
}
try {
switch ($action) {
case "save":
$anzahl = preiseSpeichern($body["reihe"] ?? "", $body["zeilen"] ?? []);
// Die gespeicherte Fassung zurueckgeben: die Maske zeigt danach
// die abgeleiteten Enddaten, nicht die eingetippten.
jsonAntwort([
"gespeichert" => $anzahl,
"zeilen" => preiseLaden($body["reihe"]),
]);
case "kacheln-save":
/*
* Fehlt "werte" oder steht dort null, faellt die Kachel auf
* ihre Vorgabe zurueck - dann kommt diese zurueck, damit die
* Maske zeigt, was jetzt gilt, statt zu leeren Zeilen.
*/
$floor = $body["floor"] ?? "";
$room = $body["room"] ?? "";
$werte = array_key_exists("werte", $body) ? $body["werte"] : null;
$gespeichert = kachelWerteSpeichern($floor, $room, $werte);
$vorgabe = [];
foreach (allRooms() as $r) {
if ($r["floor"] === $floor && $r["id"] === $room) {
$vorgabe = kachelVorgabe($r);
}
}
jsonAntwort([
"eigen" => $gespeichert !== null,
"werte" => $gespeichert !== null ? $gespeichert : $vorgabe,
]);
case "geraete-raeume":
jsonAntwort(["gespeichert" => saveRooms($body["rooms"] ?? [])]);
case "geraet-loeschen":
/*
* Loeschen ist endgueltig - abgelehnt wird es, wenn eine
* Automatik auf das Geraet zeigt (siehe geraetLoeschen()).
* Zurueck kommt die neue Liste, damit die Maske nicht raten
* muss, was jetzt gilt.
*/
$name = geraetLoeschen($body["id"] ?? 0);
jsonAntwort(["geloescht" => $name, "geraete" => geraeteListe()]);
default:
jsonAntwort(["error" => "Unbekannte Aktion."], 400);
}
} catch (InvalidArgumentException $e) {
jsonAntwort(["error" => $e->getMessage()], 400);
} catch (Throwable $e) {
jsonAntwort(["error" => "Speichern fehlgeschlagen: " . $e->getMessage()], 500);
}
}
if ($action === "kacheln") {
try {
jsonAntwort([
"kacheln" => kachelListe(),
// Alle Symbolnamen - die üblichen zuerst und mit Beschriftung.
"symbole" => kachelIconNamen(),
// Auswahlliste je Geraet - dieselbe Quelle wie im Automatik-Editor.
"katalog" => kachelKatalog(),
// Fuer die Eingabe von Hand, wenn etwas nicht im Katalog steht.
"topics" => kachelTopicVorschlaege(),
"tabelleDa" => kachelTabelleDa(),
"max" => KACHEL_MAX,
]);
} catch (Throwable $e) {
jsonAntwort(["error" => "Kacheln nicht abrufbar: " . $e->getMessage()], 500);
}
}
if ($action === "geraete") {
try {
jsonAntwort(["geraete" => geraeteListe(), "raeume" => raumListe()]);
} catch (Throwable $e) {
jsonAntwort(["error" => "Geräte nicht abrufbar: " . $e->getMessage()], 500);
}
}
if ($action === "list") {
try {
jsonAntwort(["zeilen" => preiseLaden($_GET["reihe"] ?? "")]);
} catch (InvalidArgumentException $e) {
jsonAntwort(["error" => $e->getMessage()], 400);
} catch (Throwable $e) {
jsonAntwort(["error" => "Laden fehlgeschlagen: " . $e->getMessage()], 500);
}
}
jsonAntwort(["error" => "Unbekannte Aktion."], 400);