Am Rechner liess die Karte die Bildlaufleiste erscheinen, die Zeitleiste wurde schmaler und der ResizeObserver zeichnete sie samt Karte neu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
135 lines
5.2 KiB
PHP
135 lines
5.2 KiB
PHP
<?php
|
||
|
||
require_once("./phpMQTT.php");
|
||
require_once("../helper.php");
|
||
|
||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||
header("Content-Type: application/json; charset=utf-8");
|
||
|
||
if (!checkLogin()) {
|
||
http_response_code(401);
|
||
echo json_encode(["success" => false, "message" => "Nicht angemeldet."]);
|
||
exit;
|
||
}
|
||
|
||
$topic = $_POST["topic"] ?? "";
|
||
$payload = $_POST["payload"] ?? "";
|
||
$allowedTopics = [
|
||
"Gartenwasser/vorn/set",
|
||
"Gartenwasser/vorn/auto",
|
||
"Gartenwasser/hinten/set",
|
||
"Gartenwasser/hinten/auto"
|
||
];
|
||
|
||
if (!in_array($topic, $allowedTopics, true)) {
|
||
http_response_code(400);
|
||
echo json_encode(["success" => false, "message" => "Nicht erlaubtes MQTT-Topic."]);
|
||
exit;
|
||
}
|
||
|
||
if (str_ends_with($topic, "/set")) {
|
||
$command = json_decode($payload, true);
|
||
$validValve = is_array($command)
|
||
&& isset($command["valve"], $command["set"])
|
||
&& in_array((int) $command["valve"], [1, 6], true)
|
||
&& in_array($command["set"], ["open", "close"], true);
|
||
if ($validValve && $command["set"] === "open") {
|
||
$validValve = isset($command["timer"])
|
||
&& is_numeric($command["timer"])
|
||
&& (int) $command["timer"] >= 1
|
||
&& (int) $command["timer"] <= 120;
|
||
}
|
||
if (!$validValve) {
|
||
http_response_code(400);
|
||
echo json_encode(["success" => false, "message" => "Ungültiger Ventilbefehl."]);
|
||
exit;
|
||
}
|
||
$payload = json_encode($command, JSON_THROW_ON_ERROR);
|
||
} elseif (!in_array($payload, ["Hoch", "Vorn", "Trog", "Stop"], true)) {
|
||
http_response_code(400);
|
||
echo json_encode(["success" => false, "message" => "Ungültiger Automatikbefehl."]);
|
||
exit;
|
||
}
|
||
|
||
try {
|
||
$mqtt = new Bluerhinos\phpMQTT("localhost", 1883, "WateringWeb-" . bin2hex(random_bytes(4)));
|
||
if (!$mqtt->connect(true, null, "", "")) {
|
||
http_response_code(503);
|
||
echo json_encode(["success" => false, "message" => "MQTT-Broker nicht erreichbar."]);
|
||
exit;
|
||
}
|
||
$mqtt->publish($topic, $payload, 0, false);
|
||
$mqtt->close();
|
||
} catch (Throwable $error) {
|
||
http_response_code(503);
|
||
echo json_encode(["success" => false, "message" => "MQTT-Fehler: " . $error->getMessage()]);
|
||
exit;
|
||
}
|
||
echo json_encode(["success" => true, "topic" => $topic, "payload" => $payload]);
|
||
exit;
|
||
}
|
||
|
||
if (!checkLogin()) {
|
||
exit;
|
||
}
|
||
|
||
// Zonen des Fensters. Die Reihenfolge bestimmt die Reihenfolge der Karten;
|
||
// die Keys muessen zu wateringZones in js/solar/bewaesserungAnzeige.js passen,
|
||
// "bild" zu ZONENBILDER in js/solar/energiefluss.js. "dauern" sind die
|
||
// Schnellwahlen in Minuten, die erste ist die Vorgabe.
|
||
$zonen = [
|
||
["key" => "troughs", "label" => "Tröge", "bild" => "kuebel", "dauern" => [5, 10, 15, 30]],
|
||
["key" => "raisedBeds", "label" => "Beete", "bild" => "hochbeet", "dauern" => [30, 15, 45, 60]],
|
||
["key" => "frontGarden", "label" => "Vorn", "bild" => "garten", "dauern" => [30, 15, 45, 60]],
|
||
];
|
||
|
||
// Die Abläufe der Ventilsteuerung (Topic .../auto). Mehrere Einträge in
|
||
// "modi" starten bzw. stoppen gemeinsam.
|
||
$ablaeufe = [
|
||
["label" => "Tröge + Beete", "modi" => ["Gartenwasser/vorn" => "Trog", "Gartenwasser/hinten" => "Hoch"]],
|
||
["label" => "Tröge", "modi" => ["Gartenwasser/vorn" => "Trog"]],
|
||
["label" => "Beete", "modi" => ["Gartenwasser/hinten" => "Hoch"]],
|
||
["label" => "Vorn", "modi" => ["Gartenwasser/vorn" => "Vorn"]],
|
||
];
|
||
?>
|
||
<div class="lade wasser">
|
||
<div class="lade-abschnitt">
|
||
<h3>Abläufe</h3>
|
||
<div class="lade-chips wasser-ablaeufe">
|
||
<?php foreach ($ablaeufe as $ablauf): ?>
|
||
<button type="button" class="lade-chip" aria-pressed="false"
|
||
data-ablauf="<?= htmlspecialchars(json_encode($ablauf["modi"], JSON_UNESCAPED_SLASHES)) ?>"><?= htmlspecialchars($ablauf["label"]) ?></button>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<div class="lade-erklaerung">Ein Ablauf gießt die Zonen nacheinander – antippen startet, nochmal antippen stoppt. Die Regenautomatik läuft davon unabhängig zum Sonnenaufgang.</div>
|
||
</div>
|
||
|
||
<div class="wasser-zonen">
|
||
<?php foreach ($zonen as $zone):
|
||
$dauern = $zone["dauern"];
|
||
sort($dauern); ?>
|
||
<div class="wasser-zone" data-zone="<?= $zone["key"] ?>" data-dauer="<?= $zone["dauern"][0] ?>">
|
||
<div class="wasser-kopf">
|
||
<span class="wasser-bild" data-bild="<?= $zone["bild"] ?>" aria-hidden="true"></span>
|
||
<div class="wasser-titel">
|
||
<b><?= htmlspecialchars($zone["label"]) ?></b>
|
||
<span data-w="zustand">–</span>
|
||
</div>
|
||
<span class="lade-pille" data-w="pille"></span>
|
||
</div>
|
||
<div class="wasser-fuss">
|
||
<div class="lade-chips" role="group" aria-label="Dauer für <?= htmlspecialchars($zone["label"]) ?>">
|
||
<?php foreach ($dauern as $min): ?>
|
||
<button type="button" class="lade-chip" aria-pressed="false" data-min="<?= $min ?>"><?= $min ?> min</button>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<button type="button" class="lade-start wasser-knopf" data-w="knopf"><span class="lade-punkt"></span><span data-w="knopfText">Gießen</span></button>
|
||
</div>
|
||
<div class="wasser-info" data-w="info"></div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
<div class="lade-meldung" data-w="meldung" aria-live="polite">Befehle gehen sofort an die Ventilsteuerung</div>
|
||
</div>
|