From 5e98b71b82b1e002b4814e07e67f75f536158a15 Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 31 Aug 2026 01:03:26 +0200 Subject: [PATCH] DOCS-SYNC: README + RECOVERY + NETATMO.md aktualisiert, CHANGELOG neu README.md: - Architektur-Diagramm: clock_wordclock + netatmo ergaenzt - Neue Sektion 'Shared Foundation' (palette.py + plugins/base.py) - Neue Sektion 'DeepSleep / Energie' (Weckzeiten, CPU-Throttle, /power Route) - Plugin-Tabelle korrigiert: alle Config-Felder auf aktuellen Stand (system: show_uptime/show_load/compact, strava: client_id/secret/refresh_token, spotify: Last.fm statt Spotify API, gmail: oauth_token_json, minimax: subscription_key, netatmo: client_id/secret/refresh_token) - Eigenes-Plugin-Sektion: Hinweis auf shared helper-Nutzung - Quick-Start config.json mit power-Block-Beispiel RECOVERY.md: - Neue Sektion 'Display-Refresh aus Admin-UI erzwingen' (POST /api/wake) - Neue Sektion 'DeepSleep-Fehlkonfiguration' (manueller Fix via SSH/Recovery-AP) plugins/NETATMO.md: - Sektion 3: Slot-Tabelle aktualisiert (compact / compact_2x2 / full_4x4) - Neues V1-Status-Update ASCII-Layout mit allen Sektionen - Design-Regeln explizit aufgelistet - Sektion 4 Optionen auf aktuellen Stand (refresh_token statt username/password, show_forecast statt show_secondary/show_compass, bar_gradient weg) - Sektion 6 Technische Details: Forecast-Quelle Open-Meteo, neue interne Methoden (_render_compact_2x2, _render_full_4x4, _get_12h_history, _get_forecast), shared helper explizit aufgelistet CHANGELOG.md (neu): - Keep-a-Changelog-Format mit [Unreleased] fuer aktuelle Aenderungen - FEAT-DEEPSLEEP + FEAT-NETATMO-06 + REFACTOR-PLUGINS dokumentiert - 'Earlier' Sektion mit letztem Git-Log der NETATMO-Iterationen --- CHANGELOG.md | 45 +++++++++++++++++++ README.md | 109 +++++++++++++++++++++++++++++++------------- RECOVERY.md | 36 +++++++++++++++ plugins/NETATMO.md | 110 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 252 insertions(+), 48 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a31179e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,45 @@ +# Changelog + +Alle nennenswerten Änderungen an epaper-dashboard, neueste zuerst. +Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/). + +Convention: Commit-Messages folgen `FEAT-XXX-NN: ...` / `FIX-XXX-NN: ...` / +`REFACTOR-XXX-NN: ...` Schema. + +## [Unreleased] + +### Added +- **DeepSleep / Energie-Tab** — Display-Weckzeiten, CPU-Throttle (600MHz), + manuelles Wecken via Admin-UI (`/power`, `/api/power`, `/api/wake`). + ZZZ-Indikator + Throttle-Badge im Sleep. 60s-Sleep-Chunks in main loop. +- **Shared Foundation** — `palette.py` + `plugins/base.py` als Single Source + of Truth für Farben, deutsche Datums-Formatter, Render-Helper. + Helper: `draw_battery`, `draw_compass`, `draw_trend`, `draw_line_chart`, + `draw_mini_bar`, `draw_weather_icon`, `draw_zzz_indicator`, + `draw_deepsleep_indicator`, `batt_color`, `co2_color`, `temp_color`, + `wmo_to_icon`, `de_weekday_long/short`, `de_date`, `de_time`. + +### Changed +- **Netatmo: V1-Status-Update Redesign** (FEAT-NETATMO-06) — 4-Sektionen + (Aussen, Wind+Regen, Indoor, Vorhersage), echte 12h-History für MIN/MAX, + dynamische Forecast-Daten (`datetime.now() + timedelta`), 7-Farben-Palette + durchgehend, deutsche Strings. +- **Plugin-Konsolidierung** — `weather.py` nutzt jetzt `draw_compass`/ + `draw_weather_icon`/`temp_color` aus den shared helpers (kein Custom-Code + mehr). `strava.py`, `system.py`, `minimax.py`, `clock_wordclock.py` + auf durchgehend deutsche Strings umgestellt. Doppeltes `label`-Artefakt + in `strava.py` entfernt. +- **`clock_wordclock.py`** — locale-abhängige `strftime("%A")` durch + `de_weekday_long()` ersetzt (war auf nicht-`de_DE`-Systemen Englisch). + +## [Earlier] — git log + +``` +5de086e FEAT-DEEPSLEEP: Display-Refresh-Timer + CPU-Throttle + Admin Power-Tab +5a83826 FEAT-NETATMO-06: V1 Status-Update Redesign + shared helpers foundation +c5a0983 FIX-NETATMO-05: ACeP Native-Farben + bessere Spalten-Verhaeltnisse +c55cc90 FIX-NETATMO-04: Hintergrund auf echtes Weiss fuer ACeP-Display +1aa11f5 FEAT-NETATMO-03: Luftdruck + 3-Tage Forecast + Überstände-Fix +fe1c06b FEAT-NETATMO-02: Komplettes Redesign auf 4x4 WarmNews-Layout +9b91598 FIX-NETATMO-01: Netatmo-Plugin an 2025-API anpassen + /config-Bug fixen +``` diff --git a/README.md b/README.md index 58c8488..fd82e46 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ Plugin-based dashboard for the **Waveshare 7.3" ACeP 7-Color e-Paper (F) HAT** on Raspberry Pi 4. -Rendert alle 180s (oder konfigurierbar) ein 800×480px Vollbild auf dem Display. +Rendert regelmäßig (Standard 180s, oder konfigurierbar; im DeepSleep-Modus nur zu +Weckzeiten) ein 800×480px Vollbild auf dem Display. ## Hardware @@ -13,26 +14,44 @@ Rendert alle 180s (oder konfigurierbar) ein 800×480px Vollbild auf dem Display. ## Architektur ``` -┌─────────────────────────────────────────────┐ -│ epaper-dashboard │ -├──────────────────┬──────────────────────────┤ -│ dashboard.py │ admin.py │ -│ (Renderer) │ (Web Admin UI :8080) │ -├──────────────────┴──────────────────────────┤ -│ layout.py · 4×4 Grid · Pack-Algorithmus │ -├────────────────────────────────────────────┤ -│ plugins/ (eines pro Widget) │ -│ clock · weather · system · spotify │ -│ strava · gmail · minimax · hello │ -├────────────────────────────────────────────┤ -│ network_watchdog.py │ -│ (WiFi AP/Client Management) │ -├────────────────────────────────────────────┤ -│ waveshare_epd/ (Vendor-Treiber) │ -│ epd7in3f.py │ -└─────────────────────────────────────────────┘ +┌──────────────────────────────────────────────┐ +│ epaper-dashboard │ +├──────────────────┬───────────────────────────┤ +│ dashboard.py │ admin.py │ +│ (Renderer + │ (Web Admin UI :8080) │ +│ DeepSleep) │ │ +├──────────────────┴───────────────────────────┤ +│ layout.py · 4×4 Grid · Pack-Algorithmus │ +├───────────────────────────────────────────────┤ +│ plugins/ (eines pro Widget) │ +│ clock · clock_wordclock · weather · system │ +│ spotify · strava · gmail · minimax · │ +│ netatmo · hello │ +├───────────────────────────────────────────────┤ +│ shared: palette.py · plugins/base.py │ +│ (Farben, Formatter, Render-Helper) │ +├───────────────────────────────────────────────┤ +│ network_watchdog.py │ +│ (WiFi AP/Client Management) │ +├───────────────────────────────────────────────┤ +│ waveshare_epd/ (Vendor-Treiber) │ +│ epd7in3f.py │ +└───────────────────────────────────────────────┘ ``` +### Shared Foundation (Single Source of Truth) + +- **`palette.py`** — 7-Farben ACeP-Palette (`BLACK, WHITE, RED, GREEN, BLUE, YELLOW, ORANGE`), + semantische Aliase (`FG, BG, OK, WARN, ALERT, INFO, ACCENT`), deutsche Datums-Formatter + (`de_weekday_long`, `de_weekday_short`, `de_date`, `de_weekday_date`, `de_time`), + `temp_color()` / `co2_color()` / `batt_color()`, Wetter-Icon-Mapping (`wmo_to_icon`). +- **`plugins/base.py`** — `Widget`-Basisklasse, Render-Helper + (`draw_battery`, `draw_compass`, `draw_trend`, `draw_line_chart`, `draw_mini_bar`, + `draw_weather_icon`, `draw_zzz_indicator`, `draw_deepsleep_indicator`), + Layout-Utilities (`is_small`, `is_wide`, `is_tall`). + +Alle Plugins nutzen diese Helper — keine duplizierte Render-Logik. + ## Quick Start ### Pi vorbereiten @@ -54,7 +73,7 @@ cd epaper-dashboard cp config.example.json config.json # → config.json editieren (Plugins + Layout) -#waveshare_epd Treiber +# waveshare_epd Treiber git clone https://github.com/waveshareteam/Waveshare_GPIO.git waveshare_epd_lib # oder: den waveshare_epd Ordner vom vorherigen Setup übernehmen @@ -71,6 +90,11 @@ chmod +x install_services.sh { "version": 2, "refresh_interval_s": 180, + "power": { + "deepsleep_enabled": false, + "wake_times": ["07:00", "12:00", "18:00"], + "cpu_throttle": false + }, "layout": { "grid": { "cols": 4, "rows": 4 }, "items": [ @@ -96,6 +120,7 @@ http://pi:8080/ - **Layout-Editor** — Items per Klick hinzufügen, verschieben, Größe ändern, Auto-Pack - **Plugin-Config** — API-Keys, Locations, etc. pro Widget +- **Energie-Tab** — DeepSleep-Modus, Weckzeiten, CPU-Throttle, manuelles Display-Aufwecken - **Refresh Now** — sofortiger Display-Refresh - **Netzwerk** — WLAN wechseln ohne SSH @@ -104,23 +129,40 @@ Default Login: `admin` / `admin` — in `.env` mit `EPAPER_ADMIN_PASSWORD` setze ## Plugins | Plugin | Datenquelle | Config-Felder | -|--------|-------------|---------------| -| `clock` | Systemzeit | — | -| `weather` | Open-Meteo (kein API-Key) | `location` (lat,lon), `show_uv`, `show_forecast_hours` | -| `system` | Pi CPU/RAM/Uptime | `show_uptime`, `show_load`, `show_temp` | -| `spotify` | Spotify Web API | `client_id`, `client_secret` (via Spotify Dev Portal) | -| `strava` | Strava API | `access_token`, `club_id` | -| `gmail` | Gmail API | `credentials_json` (OAuth2) | -| `minimax` | MiniMax AI | `api_key`, `model`, `prompt` | -| `netatmo` | Netatmo Weather API (OAuth2) | `client_id`, `client_secret`, `username`, `password` (Details: [NETATMO.md](plugins/NETATMO.md)) | -| `hello` | statisch | `text`, `color`, `size` | +|---|---|---| +| `clock` | Systemzeit | `format_24h`, `show_seconds`, `show_date`, `show_weekday`, `accent_color` | +| `clock_wordclock` | Systemzeit | `show_date`, `show_weekday`, `show_es_ist`, `invert`, `accent_color` (QlockTwo-Style Wort-Uhr) | +| `weather` | Open-Meteo (kein API-Key) | `location` (lat,lon), `show_uv`, `show_forecast_hours`, `show_wind_compass` | +| `system` | Pi CPU/RAM/Uptime | `show_uptime`, `show_load`, `compact`, `bar_thresholds`, `bar_gradient` | +| `spotify` | Last.fm Scrobble | `api_key`, `username` | +| `strava` | Strava API | `client_id`, `client_secret`, `refresh_token` | +| `gmail` | Gmail API | `oauth_token_json` | +| `minimax` | MiniMax Token Plan | `subscription_key`, `show_credits`, `api_base`, `bar_thresholds`, `bar_gradient` | +| `netatmo` | Netatmo Weather API (OAuth2) | siehe [plugins/NETATMO.md](plugins/NETATMO.md) | +| `hello` | statisch | `text`, `color` | + +## DeepSleep / Energie + +Das Dashboard unterstützt einen **DeepSleep-Modus** für stromsparenden 24/7-Betrieb: + +- **Weckzeiten** (z.B. `["07:00", "12:00", "18:00"]`) — Display wacht zu diesen Zeiten auf, + rendert neu, schläft wieder. +- **CPU-Throttle** (Pi auf 600MHz im Sleep) — spart ~1.5W am Raspberry Pi. +- **Manuelles Wecken** — Button im Admin-UI unter `/power` triggert sofortigen Refresh. +- **ZZZ-Indikator** — `draw_zzz_indicator` aus `plugins/base.py` zeigt im Sleep-Zustand + dezent "zZz" oben links. +- **60s-Sleep-Chunks** — Main-Loop schläft in 1-Minuten-Häppchen statt eines langen + Intervalls, damit das Weck-Signal schnell greift. + +Konfiguration in der Admin-UI (`/power`) oder direkt in `config.json` unter `power.*`. +Defaults werden beim ersten Start aus `POWER_DEFAULTS` in `palette.py` auto-gefüllt. ## Eigenes Plugin schreiben ```python # plugins/my_widget.py from plugins.base import Widget -from palette import FG, BG +from palette import FG, BG, de_weekday_date class Widget(Widget): name = "my_widget" @@ -140,12 +182,17 @@ class Widget(Widget): def render(self, draw, fonts, x, y, w, h): d = self.fetch() # w, h sind Pixel (nicht Zellen!) + # Nutze die shared helper aus palette + base draw.text((x + 10, y + 10), f"Value: {d['value']}", font=fonts["28"], fill=FG) ``` **Palette:** `BLACK, WHITE, RED, GREEN, BLUE, YELLOW, ORANGE` + semantisch `FG, BG, OK, WARN, ALERT, INFO, ACCENT` +**Tipp:** Vermeide eigene `draw_compass`/`draw_weather_icon`/etc. — nutze die Helper +aus `plugins/base.py`. Sonst dupliziert sich die Render-Logik und das Design driftet +auseinander (siehe Commit-History FEAT-NETATMO-06). + ## Services ```bash diff --git a/RECOVERY.md b/RECOVERY.md index e5ad183..3652b24 100644 --- a/RECOVERY.md +++ b/RECOVERY.md @@ -39,3 +39,39 @@ Falls Strom-Reset nicht hilft (z.B. weil Profil `netplan-wlan0-IoT` kaputt ist): - Watchdog-Code war korrekt; das Problem ist die PolicyKit-Konfiguration - Polkit-Restart nach Rule-Update: besser nur `polkitd` SIGHUP schicken, nicht systemctl restart (das hat in dieser Session offenbar den Polkit-Daemon in einem inkonsistenten Zustand hinterlassen) + +## Display-Refresh aus Admin-UI erzwingen + +Falls das Display im DeepSleep-Modus ist (z.B. ausserhalb der Weckzeiten) und du +es manuell wecken willst, ohne den Pi neu zu starten: + +### Option 1: Admin-UI Energie-Tab +1. Browser: `http://:8080/power` (oder `http://10.42.0.1:8080/power` im Recovery-AP) +2. Klick auf **Display wecken** — triggert `POST /api/wake`, Dashboard-Refresh startet sofort +3. CPU-Throttle wird automatisch deaktiviert, Display rendert, geht zurück in Sleep + +### Option 2: Per curl direkt +```bash +curl -X POST http://:8080/api/wake +# Response: {"ok": true, "woken_at": "2026-08-31T00:42:13"} +``` + +Das funktioniert auch im Recovery-AP-Modus (`10.42.0.1`) — solange der Admin-Service läuft. + +## DeepSleep-Fehlkonfiguration + +Wenn `wake_times` so gesetzt ist, dass das Display **nie** aufwacht (z.B. leere Liste +oder Einträge in der Vergangenheit), bleibt das Dashboard dauerhaft im Sleep: + +```bash +# SSH-Zugang nötig (koptikp) +ssh koptikp@ +# config.json direkt editieren: +nano /home/koptikp/.hermes/projects/pi/config.json +# → "deepsleep_enabled": false setzen +# → "wake_times": ["07:00", "12:00", "18:00"] setzen +# Service neu starten: +systemctl --user restart epaper-dashboard +``` + +Alternativ über die Recovery-AP: `http://10.42.0.1:8080/power` → DeepSleep deaktivieren. diff --git a/plugins/NETATMO.md b/plugins/NETATMO.md index 962d273..df1c13c 100644 --- a/plugins/NETATMO.md +++ b/plugins/NETATMO.md @@ -97,12 +97,59 @@ In der Admin-UI ein Netatmo-Widget auf das Grid ziehen. Das Plugin ist | Slot | Was du siehst | |---|---| -| **1×1** | Große Außen-Temperatur, Mini-CO₂/Feuchte-Status | -| **2×1** | Outdoor-Temperatur + Wind-Geschwindigkeit kompakt | -| **4×1** | Indoor · Outdoor · Wind/Regen — drei Spalten | -| **1×4** | Vertikale Liste aller Module | -| **2×2** | Indoor-Card (mit CO₂-Bar) + Outdoor-Card + Wind/Regen-Bereich | -| **4×4** | Volle Ansicht mit allen Modulen, Min/Max, Windrose | +| **1×1** | `compact`: Große Außen-Temperatur + MIN/MAX + Tag-Status | +| **2×2** | `compact_2x2`: Aussen + Wind/Regen-Bereich + Indoor-Liste | +| **4×4** | `full_4x4`: Volle V1-Status-Update Ansicht (siehe unten) | + +### V1-Status-Update Design (4×4) + +Die grosse Ansicht ist als **V1-Status-Update** designed — minimal, weisser +Hintergrund, kräftige Akzentfarben, klare Hierarchie: + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ DAHEIM Mo 31.08 00:36 │ +├──────────────┬──────────┬─────────────────────────────────────────┤ +│ AUSSEN ▮▮▮ │ WIND │ INNEN · 3 │ +│ │ N │ ┌─┐ │ +│ 12.6° │ 12 │ │M│ Daheim 21.5° │ +│ │ km/h │ └─┘ │ +│ MIN MAX F │ Bö 24 │ ▰▰▱▱▱▱▱▱ CO₂ 620 ppm ▮ 78% │ +│ 13° 21° 67% │ ─────── │ │ +│ DRUCK 1014▼ │ REGEN │ ┌─┐ │ +│ │ 0.0 │ │2│ Küche 23.5° │ +│ 12H VERLAUF │ mm/h │ └─┘ │ +│ ╱╲ │ │ ▰▰▰▰▱▱▱▱ CO₂ 980 ppm ▮ 88% │ +│ ╱ ╲ │ HEUTE │ │ +│ ╱ ╲── │ 6.2 mm │ ┌─┐ │ +│ 22°/10° jetzt│ ▮ 82% │ │3│ Schlafen 20.8° │ +│ │ │ └─┘ │ +│ │ │ ▰▰▰▰▰▱▱ CO₂ 1450 ppm ▮ 41% │ +├──────────────┴──────────┴─────────────────────────────────────────┤ +│ VORHERSAGE │ +│ MO ▮ 0.0 mm ☀ 9° 19° │ +│ DI ▮ 2.4 mm ☁ 11° 21° │ +│ MI ▮ 8.1 mm ☁ 8° 17° │ +└──────────────────────────────────────────────────────────────────┘ +``` + +**Spalten:** +- **Aussen (28%)** — Grosse Aussentemperatur + 4 Stats (MIN/MAX/FEUCHTE/DRUCK) + + 12h-Verlaufs-Chart (grüne Linie, 2 Y-Ticks min/max) +- **Wind/Regen (16%)** — beide gestapelt, Wind oben mit Compass und Bö, + Regen unten mit HEUTE-Menge und 1h/24h-Bars; jeder Block hat seine Batterie unten rechts +- **Indoor (36%)** — pro Sensor eine Zeile: rote Tag-Box (M/2/3) | Name | grosser + Temp-Wert (22pt, in Temperatur-Farbe) | CO₂-Bar (gelb/rot je nach ppm) | CO₂-Wert + Batterie +- **Vorhersage (20%)** — pro Tag: Tag-Name + Regentropfen-Icon + Regenmenge in mm + + Wetter-Icon (WMO), darunter riesige Min (blau) / Max (orange) + +**Wichtige Design-Regeln:** +- 7 ACeP-Farben nur (kein Grau, keine Verläufe, kein Anti-Aliasing) +- Wichtige Werte (Temps, Regen) dominieren visuell +- Batterie-Icons gehen in den Bottom-Right ihrer Sektion +- Indoor-Sensoren haben rote Tag-Box (NICHT schwarz) +- MIN/MAX kommen aus echter 12h-History (nicht estimated) +- Forecast-Daten dynamisch via `datetime.now() + timedelta` Das Plugin priorisiert bei der Layout-Wahl **wide/tall** vor `small`, damit 4×1- und 1×4-Slots nicht in die Mini-Ansicht fallen. @@ -115,20 +162,27 @@ damit 4×1- und 1×4-Slots nicht in die Mini-Ansicht fallen. |---|---|---|---| | `client_id` | secret | — | Netatmo App Client-ID | | `client_secret` | secret | — | Netatmo App Client-Secret | -| `username` | secret | — | Netatmo Login (E-Mail) | -| `password` | secret | — | Netatmo Passwort (nur RAM) | +| `refresh_token` | secret | — | OAuth2 Refresh-Token (nur RAM, wird on-demand erneuert) | | `station_filter` | string | `""` | Substring-Filter auf Stations-/Modulname | -| `show_indoor` | bool | `true` | Hauptmodul + zusätzliche Indoor-Sensoren anzeigen | | `show_outdoor` | bool | `true` | NAModule1 (Außen) anzeigen | | `show_wind` | bool | `true` | NAModule2 (Wind) anzeigen | | `show_rain` | bool | `true` | NAModule3 (Regen) anzeigen | -| `show_compass` | bool | `true` | Windrose in der Wind-Card zeichnen | -| `show_secondary` | bool | `true` | Min/Max + letzte Aktualisierung | +| `show_indoor` | bool | `true` | Hauptmodul + zusätzliche Indoor-Sensoren anzeigen | +| `show_forecast` | bool | `true` | Open-Meteo 3-Tage-Vorhersage anzeigen | | `co2_thresholds` | string | `ok@600,warn@1000,alert@1500` | CO₂-Bar Schwellen (ppm) | -| `bar_gradient` | bool | `true` | Verlaufsmodus der Bar | | `temp_unit` | select | `C` | `C` oder `F` | | `wind_unit` | select | `kmh` | `kmh` oder `ms` | +### Auth-Flow (aktualisiert) + +Das Plugin verwendet **OAuth2 mit Refresh-Token-Grant** (kein Passwort-Grant mehr). +Beim ersten Setup musst du einmalig einen Refresh-Token holen — das geht z.B. mit +dem Netatmo-Developer-Portal oder dem offiziellen OAuth-Tool. Danach wird der +Token automatisch im RAM gecacht und alle 3h erneuert. + +Falls du noch alte `username`/`password`-Config-Felder in deiner `config.json` hast: +diese werden ignoriert. Setze statt dessen `refresh_token`. + ### CO₂-Schwellen anpassen `co2_thresholds` ist ein String im Format `farbe@ppm_in_ppm`. @@ -181,21 +235,43 @@ wird ein neuer Token geholt. | Aspekt | Wert | |---|---| -| API-Version | Netatmo Connect OAuth2 | +| API-Version | Netatmo Connect OAuth2 (Refresh-Token-Grant) | | Endpoints | `POST /oauth2/token`, `GET /api/getstationsdata` | +| Forecast-Quelle | Open-Meteo (`/v1/forecast`) — kein API-Key | | Token-Lebensdauer | 10800s (3h), Refresh on the fly | | Cache | In-Memory, kein Disk-IO pro Render | -| Datenquelle | Netatmo Cloud (Update alle ~10 Min) | +| Datenquelle Netatmo | Netatmo Cloud (Update alle ~10 Min) | | Modul-Typen | NAMain, NAModule1..4 | | `reachable`-Feld | „true" wenn das Modul in den letzten 4h gesehen wurde | +### Wichtige interne Methoden + +- `_render_compact(x, y, w, h, ...)` — 1×1-Mini-Ansicht +- `_render_compact_2x2(x, y, w, h, ...)` — 2×2-Ansicht +- `_render_full_4x4(x, y, w, h, ...)` — V1-Status-Update für 4×4 +- `_get_12h_history(...)` — 12h-Temperaturverlauf (Quelle: Netatmo `getmeasure` API) +- `_get_forecast(lat, lon, days=3)` — Open-Meteo 3-Tage-Vorhersage + +### Shared Helper (aus `plugins/base.py` + `palette.py`) + +Das Plugin nutzt konsequent die zentralen Render-Helper: +- `draw_battery()`, `batt_color()` — Batterie-Icon mit 3-stufiger Farbe +- `draw_compass()` — Windrose (mit N/O/S/W-Beschriftung optional) +- `draw_weather_icon()`, `wmo_to_icon()` — 7 Wetter-Zustände (sun/cloud/rain/storm/snow/fog/partly) +- `draw_line_chart()` — 12h-Verlaufs-Chart mit Y-Grid +- `draw_mini_bar()` — 1h/24h-Regen-Bars +- `de_weekday_long/short`, `de_date`, `de_time` — deutsche Datums-/Zeit-Formatter (locale-frei) +- `temp_color()`, `co2_color()` — semantische Farben nach Schwellen + ### Was wird pro Refresh gemacht? 1. Prüfe Token-Cache (RAM). Wenn abgelaufen oder fehlend → hole neuen - Token via Password-Grant (initial) oder Refresh-Grant. + Token via Refresh-Grant. 2. `GET /api/getstationsdata?get_favorites=false` mit Bearer-Token. -3. Parse Antwort, filtere nach `station_filter` und sichtbaren Modulen. -4. Rendere je nach Slot-Größe (`small` / `wide` / `tall` / `standard`). +3. Hole 12h-History (`getmeasure`) für MIN/MAX-Berechnung. +4. Hole 3-Tage-Forecast von Open-Meteo. +5. Parse Antwort, filtere nach `station_filter` und sichtbaren Modulen. +6. Rendere je nach Slot-Größe (`compact` / `compact_2x2` / `full_4x4`). Bei 401 wird der Token-Cache geleert und **einmal** neu authentifiziert. Wenn das auch fehlschlägt → roter Error-Banner mit der genauen HTTP-Meldung. \ No newline at end of file