diff --git a/README.md b/README.md index f177b21..931b317 100644 --- a/README.md +++ b/README.md @@ -192,15 +192,20 @@ genau die Topics, die auf den Kacheln stehen (`tileTopics()` in `rooms.php`). | `settings` | `settings.php` | `settings.js`, `grundriss.js`, `energieflussKatalog.js`, `energiefluss.js`, `energieflussEinstellungen.js` | `settings.php?action=…` | — | | `logs` | `logs.php` | `logs.js` | `logs.php?action=…` | — | | `einfuehrung` | `einfuehrung.php` | `einfuehrung.js` | nichts — Folien und Bilder stehen in der Seite | — | -| `anzeige` | `anzeige.php` (ganze Seite, ohne `header.php`/`footer.php`) | `anlageKatalog.js`, `anlage.js`, `speicher.js`, `energieflussKatalog.js`, `energiefluss.js`, `bewaesserungAnzeige.js`, `anzeige.js` | `speicher` | `solarManager/#`, `Gartenwasser/#` | +| `anzeige` | `solar.php` im Anzeige-Modus | wie `solar`, dazu `anzeige.js` | wie `solar` | wie `solar` | -**Vollbildanzeige** (`?action=anzeige`) — Übersicht, Anlage und Speicher für ein -festes Display, gebaut für den Raspberry Pi 3B+ mit 800 × 480 im Kioskmodus: -schmale Leiste links, immer quer, nach zwei Minuten ohne Berührung zurück zur -Übersicht, MQTT verbindet still neu (Punkt unten: grün/gelb/rot), alle sechs -Stunden lädt die Seite neu. Ohne weitere Parameter läuft sie „ruhig“ — nur die -Flüsse bewegen sich, in groben Stufen — und ohne Mauszeiger; -`&animation=1` schaltet alle Animationen ein, `&maus=1` zeigt den Zeiger. +**Anzeige-Modus** (`?action=anzeige`) — die Solar-Seite für ein festes Display, +gebaut für den Raspberry Pi 3B+ mit 800 × 480 im Kioskmodus. In `index.php` eine +Kopie des Eintrags `solar` mit `"anzeige" => true`: `header.php` lässt Kopfleiste +und Menü weg und setzt eine schmale Leiste (Übersicht, Anlage, Speicher, +Diagramme), `footer.php` den Fuß; die Realtime-Karte füllt einen Bildschirm, +die Übersicht bleibt quer. Bedienfenster, Diagramme und Bewässerung kommen +unverändert aus `solarMQTT.js`. `anzeige.js` ergänzt nur: zurück zur Übersicht +nach zwei Minuten ohne Berührung (offene Fenster schließen), Verbindungspunkt +(grün/gelb/rot) und Uhr in der Leiste, Neuladen alle sechs Stunden. Ohne +weitere Parameter läuft sie „ruhig“ — nur die Flüsse bewegen sich, in groben +Stufen — und ohne Mauszeiger; `&animation=1` schaltet alle Animationen ein, +`&maus=1` zeigt den Zeiger. Und dasselbe als Abhängigkeitsbild — von der Seite bis in den Speicher: diff --git a/css/solar.css b/css/solar.css index 556cce3..2917e97 100644 --- a/css/solar.css +++ b/css/solar.css @@ -3869,22 +3869,19 @@ svg.anl-plan.anl-hoch { max-height: none; } } /* ========================================================================== - Vollbildanzeige (restricted/anzeige.php, js/solar/anzeige.js), z.B. am - Raspberry Pi mit 800 x 480: schmale Leiste links, Ansicht auf voller Höhe. + Anzeige-Modus (index.php?action=anzeige, js/solar/anzeige.js): die + Solar-Seite auf einem festen Display, z.B. Raspberry Pi mit 800 x 480. + Leiste links; die Realtime-Karte füllt genau einen Bildschirm, die + Diagramme folgen darunter und rasten beim Wischen karteweise ein. ========================================================================== */ -body.anzeige { - margin: 0; height: 100vh; overflow: hidden; - display: grid; grid-template-columns: 3.2rem minmax(0, 1fr); - background: var(--ton-grund, #191d20); color: var(--ton-schrift, #e8ede9); - font-family: "Poppins", system-ui, sans-serif; font-size: 14px; - -webkit-tap-highlight-color: transparent; user-select: none; -} +html:has(body.anzeige) { scroll-snap-type: y proximity; scrollbar-width: none; } +html:has(body.anzeige)::-webkit-scrollbar { display: none; } +body.anzeige { -webkit-tap-highlight-color: transparent; } body.anzeige-ohne-maus, body.anzeige-ohne-maus * { cursor: none !important; } -/* Die Seite lädt AdminLTE nicht - dessen Grundregeln fehlen hier. */ -body.anzeige [hidden] { display: none !important; } -body.anzeige *, body.anzeige *::before, body.anzeige *::after { box-sizing: border-box; } + .anzeige .anzeige-leiste { + position: fixed; left: 0; top: 0; bottom: 0; width: 3.2rem; z-index: 1030; display: flex; flex-direction: column; align-items: center; gap: .4rem; padding: .5rem 0; background: var(--ton-flaeche, #23282c); border-right: 1px solid var(--ton-linie, rgba(138, 148, 158, .2)); } @@ -3898,14 +3895,26 @@ body.anzeige *, body.anzeige *::before, body.anzeige *::after { box-sizing: bord .anzeige .anzeige-punkt.warn { background: #e8a33a; } .anzeige .anzeige-punkt.gut { background: #6cbe58; } .anzeige .anzeige-uhr { font-size: .72rem; font-weight: 600; color: var(--ton-schrift-2, #9aa6ad); font-variant-numeric: tabular-nums; } -.anzeige .anzeige-inhalt { min-width: 0; height: 100vh; } -.anzeige .anzeige-flaeche { box-sizing: border-box; height: 100vh; padding: .35rem; overflow-y: auto; scrollbar-width: none; } -.anzeige .anzeige-flaeche::-webkit-scrollbar { display: none; } -.anzeige .anzeige-flaeche[hidden] { display: none; } -.anzeige #anzeige-fluss { overflow: hidden; padding: .2rem; } -.anzeige #anzeige-fluss svg.enf { width: 100%; height: 100%; max-height: none; } -/* Anlage und Speicher: die Umbrüche der Solar-Seite richten sich nach der - Fensterbreite und würden am 800er-Display zu früh greifen. */ + +.anzeige .app-wrapper { display: block; } +.anzeige .app-main { margin-left: 3.2rem; } +.anzeige .app-content-header { display: none; } +.anzeige .app-content { padding: 0 .35rem; } +.anzeige .app-content .container-fluid { padding: 0; } +.anzeige .app-content .row { --bs-gutter-x: 0; } +.anzeige .app-content .card { scroll-snap-align: start; } + +/* Realtime-Karte: ein ganzer Bildschirm, ohne Kopf - die Leiste ersetzt ihn. */ +.anzeige .card#energieflussKarte { height: 100vh; margin-bottom: .5rem !important; border: 0; border-radius: 0; background: transparent; } +.anzeige .card#energieflussKarte .card-header { display: none !important; } +.anzeige .card#energieflussKarte .card-body { height: 100%; padding: .2rem 0 !important; } +.anzeige #energiefluss { height: 100%; overflow: hidden; } +.anzeige #energiefluss svg.enf { width: 100%; height: 100%; max-height: none; } +.anzeige #anlage, +.anzeige #speicher { height: 100%; overflow-y: auto; scrollbar-width: none; } + +/* Die Umbrüche von Anlage und Speicher richten sich nach der Fensterbreite + und würden am 800er-Display zu früh greifen. */ .anzeige .anl svg.anl-plan { max-height: calc(100vh - 7.5rem); } .anzeige .spk .spk-kennzahlen { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .35rem; } .anzeige .spk .spk-kachel { padding: .4rem .55rem .45rem; } @@ -3921,6 +3930,12 @@ body.anzeige *, body.anzeige *::before, body.anzeige *::after { box-sizing: bord .anzeige .spk .spk-werte small { font-size: .62rem; } .anzeige .spk .spk-gross b { font-size: 1.4rem; } +/* Bedienfenster: passen auf 480 px Höhe und lassen sich mit dem Finger bedienen. */ +.anzeige .modal-dialog { margin: .4rem auto; } +.anzeige .modal-body { max-height: calc(100vh - 9rem); overflow-y: auto; } +.anzeige .modal .form-range { height: 2rem; } +.anzeige .modal .btn { min-height: 2.4rem; } + /* Ruhig (Vorgabe am Pi): alles Zierwerk aus, nur die Flüsse laufen - in groben Stufen, damit ein Raspberry Pi 3 nicht dauernd neu zeichnet. */ .anzeige-ruhig *, @@ -3932,7 +3947,6 @@ body.anzeige *, body.anzeige *::before, body.anzeige *::after { box-sizing: bord .anzeige-ruhig .enf .enf-rueck .enf-strom { animation-direction: reverse !important; } .anzeige-ruhig .enf .enf-still .enf-strom, .anzeige-ruhig .enf.enf-pause .enf-strom { animation: none !important; } -.anzeige-ruhig .enf .enf-strahlen, .anzeige-ruhig .enf .enf-koerper { transition: none; } /* --- Karte: Umschalter Übersicht / Anlage -------------------------------- */ diff --git a/index.php b/index.php index cb2da1a..a196baa 100644 --- a/index.php +++ b/index.php @@ -120,13 +120,13 @@ if (isset($_GET["addUser"])) { "scripts" => ["js/solar/logs.js"]], "einfuehrung" => ["template" => "einfuehrung.php", "mqtt" => false, "charts" => false, "meteogram" => false, "leaflet" => false, "scripts" => ["js/solar/einfuehrung.js"]], - // Vollbild für ein festes Display (Raspberry Pi). "eigen": die Vorlage - // ist eine ganze Seite, ohne header.php und footer.php. - "anzeige" => ["template" => "anzeige.php", "eigen" => true, "mqtt" => true, "charts" => false, "meteogram" => false, "leaflet" => false, - "scripts" => ["js/solar/anlageKatalog.js", "js/solar/anlage.js", "js/solar/speicher.js", - "js/solar/energieflussKatalog.js", "js/solar/energiefluss.js", - "js/solar/bewaesserungAnzeige.js", "js/solar/anzeige.js"]], ]; + // Anzeige für ein festes Display (Raspberry Pi, 800 x 480): die Solar-Seite + // ohne Kopfleiste und Menue, mit schmaler Leiste - header.php und + // footer.php richten sich nach "anzeige", js/solar/anzeige.js macht den Rest. + $pages["anzeige"] = $pages["solar"]; + $pages["anzeige"]["anzeige"] = true; + $pages["anzeige"]["scripts"][] = "js/solar/anzeige.js"; // Unbekannte oder fehlende Aktion faellt auf die Solar-Seite zurueck. if (!isset($_GET["action"]) || !isset($pages[$_GET["action"]])) { @@ -134,13 +134,9 @@ if (isset($_GET["addUser"])) { } $page = $pages[$_GET["action"]]; - if (!empty($page["eigen"])) { - include "restricted/" . $page["template"]; - } else { - include "restricted/header.php"; - include "restricted/" . $page["template"]; - include "restricted/footer.php"; - } + include "restricted/header.php"; + include "restricted/" . $page["template"]; + include "restricted/footer.php"; } else { echo << diff --git a/js/solar/anzeige.js b/js/solar/anzeige.js index efda909..6720106 100644 --- a/js/solar/anzeige.js +++ b/js/solar/anzeige.js @@ -1,122 +1,103 @@ /* ========================================================================== - Vollbildanzeige (restricted/anzeige.php): Übersicht, Anlage und Speicher - für ein festes Display, z.B. den Raspberry Pi mit 800 x 480. + Anzeige-Modus der Solar-Seite (index.php?action=anzeige) für ein festes + Display, gebaut für den Raspberry Pi 3B+ mit 800 x 480. - Dieselben Bausteine wie auf der Solar-Seite, nur anders verdrahtet: - - immer quer (hochkantUnter: 0), das Display steht quer - - antippbar sind nur Kreise, die eine andere Ansicht öffnen; Bedienfenster - (Heizstab, Wallbox) gibt es hier nicht - - nach LEERLAUF ohne Berührung zurück zur Übersicht - - MQTT verbindet nach einem Abbruch still neu; der Punkt unten in der - Leiste zeigt den Zustand (grün verbunden, gelb keine frischen Werte, - rot getrennt). Kein alert() - am Display ist niemand, der ihn wegklickt. - - alle NEU_LADEN Stunden lädt die Seite neu, damit ein Browser, der - wochenlang läuft, keinen Speicher ansammelt und Änderungen am Code - ankommen + Die Seite selbst ist die Solar-Seite: solarMQTT.js zeichnet Übersicht, + Anlage, Speicher und Diagramme und öffnet die Bedienfenster. header.php + lässt Kopfleiste und Menü weg und setzt stattdessen die schmale Leiste + links; die Übersicht bleibt quer (energieflussStarten() in solarMQTT.js + fragt nach der Klasse "anzeige" am body). + + Hier steht nur, was ein Display ohne Bediener braucht: + - Leiste: Übersicht, Anlage, Speicher, Diagramme + - nach LEERLAUF ohne Berührung zurück zur Übersicht, ganz nach oben + - Punkt in der Leiste: grün verbunden, gelb keine frischen Werte, + rot getrennt + - alle NEU_LADEN Stunden neu laden - ein Browser, der wochenlang läuft, + sammelt sonst Speicher an, und Änderungen am Code kämen nie an ========================================================================== */ -var mqttData = {}; - (function () { "use strict"; - const ADRESSE = "wss://mqtt.nas.el-wa.org:443"; // wie in solarMQTT.js const LEERLAUF = 2 * 60000; const NEU_LADEN = 6 * 3600000; - const TAKT = typeof anzeigeRuhig !== "undefined" && anzeigeRuhig ? 2000 : 1000; const VERALTET = 30000; - const THEMEN = [ - "solarManager/#", - "Gartenwasser/vorn/Timers", "Gartenwasser/vorn/status", "Gartenwasser/vorn/WateringToday", - "Gartenwasser/hinten/Timers", "Gartenwasser/hinten/status", "Gartenwasser/hinten/WateringToday", - ]; const $ = id => document.getElementById(id); - let bild = null, anlage = null, speicher = null; - let leerlaufUhr = null, geplant = false, verbunden = false, letzteDaten = 0; + let leerlaufUhr = null; + let letzteNachricht = null, letzteZeit = 0; + function leisteSetzen(name) { + document.querySelectorAll("[data-anzeige]").forEach(b => + b.setAttribute("aria-pressed", b.dataset.anzeige === name ? "true" : "false")); + } + + function karte() { + return $("energieflussKarte"); + } + + /** Eine Ansicht der Realtime-Karte zeigen - über ihren eigenen Umschalter. */ function zeige(name) { - document.querySelectorAll("[data-anzeige]").forEach(b => b.setAttribute("aria-pressed", b.dataset.anzeige === name ? "true" : "false")); - document.querySelectorAll("[data-anzeige-flaeche]").forEach(f => { f.hidden = f.dataset.anzeigeFlaeche !== name; }); - wachHalten(); + if (name === "diagramme") { + // Die nächste Spalte nach der Realtime-Karte - dazwischen steht ein - - - - - - diff --git a/restricted/footer.php b/restricted/footer.php index 02f2a15..1eb97d2 100644 --- a/restricted/footer.php +++ b/restricted/footer.php @@ -1,3 +1,4 @@ + +