- neuer Reiter "Fahrzeug": API-Schluessel eintragen und pruefen, ohne dass ein Wert je an den Browser zurueckgeht (restricted/skodaKeys.php) - ajax/skoda.php trennt Ladungen am Zustand statt an 30 Minuten Pause und rahmt sie mit der Zeile davor und danach ein - solarLog_skoda_ladepunkte.sql: Wallbox-Verlauf waehrend einer Ladung - Kachelformat "leistung_kw" fuer Quellen, die schon Kilowatt melden - Steckersymbol versteht evPlug als 1/0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
160 lines
6.1 KiB
PHP
160 lines
6.1 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}
|
|
* GET ?action=skoda-keys Stand der Fahrzeug-Schluessel (ohne Werte!)
|
|
* POST ?action=skoda-keys-save {"felder": {"API_KEY2": "..."},
|
|
* "loeschen": ["API_KEY3"]}
|
|
*
|
|
* 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");
|
|
require_once("../restricted/skodaKeys.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()]);
|
|
|
|
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" => kachelTabelleDa(),
|
|
"max" => KACHEL_MAX,
|
|
]);
|
|
} catch (Throwable $e) {
|
|
jsonAntwort(["error" => "Kacheln 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);
|