Raumnummer * POST ?action=geraet-loeschen {"id": 12} * GET ?action=skoda-keys Stand der Fahrzeug-Schluessel (ohne Werte!) * POST ?action=skoda-keys-save {"felder": {"API_KEY2": "..."}, * "loeschen": ["API_KEY3"]} * * GET ?action=grundriss Etagen, Raeume, Kachelpositionen * POST ?action=etage-speichern {"code": "EG", "label": "...", "standard": true, "neu": false} * POST ?action=etagen-reihenfolge {"codes": ["OG", "EG", ...]} * POST ?action=etage-loeschen {"code": "EG"} * POST ?action=etage-bild multipart: code, bild (Datei) * POST ?action=raum-speichern {"nr": 0|12, "floor": "EG", "name": "...", "kuerzel": "", "thermostat": ""} * POST ?action=raum-position {"nr": 12, "x": 120, "y": 80} (x/y null = vom Plan) * POST ?action=raum-loeschen {"nr": 12} * Die Grundriss-Aktionen antworten mit dem ganzen neuen Stand. * * GET ?action=energiefluss Abweichungen der Übersicht vom Katalog * POST ?action=energiefluss-save {"knoten": [{id, aktiv, name, x, y, optionen}, ...]} * * Ein reiner Verteiler: geprueft und geschrieben wird in * restricted/costs.php, kacheln.php bzw. grundriss.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"); require_once("../restricted/skodaKeys.php"); require_once("../restricted/grundriss.php"); require_once("../restricted/energiefluss.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"; // Das Grundrissbild kommt als Formular mit Datei, nicht als JSON - deshalb // vor dem JSON-Teil. if ($_SERVER["REQUEST_METHOD"] === "POST" && $action === "etage-bild") { try { $bild = etageBildSpeichern($_POST["code"] ?? "", $_FILES["bild"] ?? null); grundriss(true); jsonAntwort(["bild" => $bild, "stand" => grundrissStand()]); } catch (InvalidArgumentException $e) { jsonAntwort(["error" => $e->getMessage()], 400); } catch (Throwable $e) { jsonAntwort(["error" => $e->getMessage()], 500); } } 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()]); case "etage-speichern": etageSpeichern($body); grundriss(true); jsonAntwort(["stand" => grundrissStand()]); case "etagen-reihenfolge": etagenReihenfolge($body["codes"] ?? null); grundriss(true); jsonAntwort(["stand" => grundrissStand()]); case "etage-loeschen": etageLoeschen($body["code"] ?? ""); grundriss(true); jsonAntwort(["stand" => grundrissStand()]); case "raum-speichern": $nr = raumSpeichern($body); grundriss(true); jsonAntwort(["nr" => $nr, "stand" => grundrissStand()]); case "raum-position": $pos = raumPosition($body["nr"] ?? 0, $body["x"] ?? null, $body["y"] ?? null); grundriss(true); jsonAntwort(["position" => $pos, "stand" => grundrissStand()]); case "raum-loeschen": raumLoeschen($body["nr"] ?? 0); grundriss(true); jsonAntwort(["stand" => grundrissStand()]); case "energiefluss-save": // Zurück kommt der gespeicherte Stand - ohne die Einträge, // die dem Katalog entsprechen. energieflussSpeichern($body["knoten"] ?? null); jsonAntwort(["einstellungen" => (object)energieflussLaden()]); case "skoda-keys-save": /* * Neue Schluessel eintragen. Zurueck kommt der neue Stand - * aber nie ein Wert, siehe restricted/skodaKeys.php. */ jsonAntwort(skodaSchluesselSpeichern( $body["felder"] ?? [], $body["loeschen"] ?? [])); default: jsonAntwort(["error" => "Unbekannte Aktion."], 400); } } catch (InvalidArgumentException $e) { jsonAntwort(["error" => $e->getMessage()], 400); } catch (RuntimeException $e) { // Nicht die Eingabe, sondern die Umgebung - Datei fehlt, Rechte // fehlen. Die Meldung sagt schon, was zu tun ist; kein Vorspann. jsonAntwort(["error" => $e->getMessage()], 500); } 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" => grundrissDa(), "max" => KACHEL_MAX, ]); } catch (Throwable $e) { jsonAntwort(["error" => "Kacheln nicht abrufbar: " . $e->getMessage()], 500); } } if ($action === "grundriss") { try { jsonAntwort(grundrissStand()); } catch (Throwable $e) { jsonAntwort(["error" => "Grundriss nicht abrufbar: " . $e->getMessage()], 500); } } if ($action === "energiefluss") { try { jsonAntwort(["einstellungen" => (object)energieflussLaden()]); } catch (Throwable $e) { jsonAntwort(["error" => "Übersicht nicht abrufbar: " . $e->getMessage()], 500); } } if ($action === "skoda-keys") { try { jsonAntwort(skodaStand()); } catch (Throwable $e) { jsonAntwort(["error" => "Schlüssel 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);