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
225 lines
8.9 KiB
Markdown
225 lines
8.9 KiB
Markdown
# epaper-dashboard
|
||
|
||
Plugin-based dashboard for the **Waveshare 7.3" ACeP 7-Color e-Paper (F) HAT** on Raspberry Pi 4.
|
||
|
||
Rendert regelmäßig (Standard 180s, oder konfigurierbar; im DeepSleep-Modus nur zu
|
||
Weckzeiten) ein 800×480px Vollbild auf dem Display.
|
||
|
||
## Hardware
|
||
|
||
- **Display:** Waveshare 7.3inch ACeP 7-Color e-Paper (F) HAT — 800×480, 7 Farben
|
||
- **Pi:** Raspberry Pi 4 (oder Zero 2 W mit Einschränkungen)
|
||
- **Interface:** SPI
|
||
|
||
## Architektur
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 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
|
||
|
||
```bash
|
||
sudo apt update && sudo apt install -y python3-pil python3-numpy python3-flask git
|
||
sudo raspi-config # → Interface Options → SPI → Enable
|
||
sudo reboot
|
||
```
|
||
|
||
### Setup
|
||
|
||
```bash
|
||
# Repository klonen
|
||
git clone https://git.pkop.de/Vibecode/epaper-dashboard.git
|
||
cd epaper-dashboard
|
||
|
||
# Config erstellen
|
||
cp config.example.json config.json
|
||
# → config.json editieren (Plugins + Layout)
|
||
|
||
# waveshare_epd Treiber
|
||
git clone https://github.com/waveshareteam/Waveshare_GPIO.git waveshare_epd_lib
|
||
# oder: den waveshare_epd Ordner vom vorherigen Setup übernehmen
|
||
|
||
# Services installieren
|
||
chmod +x install_services.sh
|
||
./install_services.sh
|
||
```
|
||
|
||
### Config
|
||
|
||
`config.json` — Version 2 Format (empfohlen):
|
||
|
||
```json
|
||
{
|
||
"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": [
|
||
{ "id": "c1", "plugin": "clock", "x": 0, "y": 0, "w": 2, "h": 2 },
|
||
{ "id": "w1", "plugin": "weather", "x": 2, "y": 0, "w": 2, "h": 2 },
|
||
{ "id": "st1", "plugin": "system", "x": 0, "y": 2, "w": 2, "h": 2 },
|
||
{ "id": "h1", "plugin": "hello", "x": 2, "y": 2, "w": 2, "h": 2 }
|
||
]
|
||
},
|
||
"plugin_configs": {
|
||
"hello": { "text": "Edit me!", "size": 40 }
|
||
}
|
||
}
|
||
```
|
||
|
||
**Grid:** 4 Spalten × 4 Zeilen = 16 Zellen à 200×120px. `x,y` = Spalte/Zeile oben-links, `w,h` = Breite/Höhe in Zellen.
|
||
|
||
### Web Admin
|
||
|
||
```
|
||
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
|
||
|
||
Default Login: `admin` / `admin` — in `.env` mit `EPAPER_ADMIN_PASSWORD` setzen.
|
||
|
||
## Plugins
|
||
|
||
| Plugin | Datenquelle | Config-Felder |
|
||
|---|---|---|
|
||
| `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, de_weekday_date
|
||
|
||
class Widget(Widget):
|
||
name = "my_widget"
|
||
label = "Mein Widget"
|
||
description = "Zeigt etwas"
|
||
category = "info"
|
||
|
||
config_schema = [
|
||
{"key": "api_key", "label": "API Key", "type": "secret"},
|
||
{"key": "interval", "label": "Intervall (s)", "type": "int", "default": 60},
|
||
]
|
||
default_config = {"api_key": "", "interval": 60}
|
||
|
||
def fetch(self):
|
||
return {"value": 42}
|
||
|
||
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
|
||
systemctl --user enable --now epaper-dashboard
|
||
systemctl --user enable --now epaper-admin
|
||
journalctl --user -u epaper-dashboard -f # Logs
|
||
```
|
||
|
||
**Wichtig:** `PrivateTmp=no` in den Service-Files — sonst sieht der Admin-Socket `/tmp/epaper-dashboard.sock` nicht.
|
||
|
||
## Display-Einschränkungen
|
||
|
||
- **Nur Full-Refresh:** ACeP-Displays vertragen keine schnellen Partial-Refreshes. Minimum 180s.
|
||
- **Refresh-Dauer:** Ein Full-Refresh dauert ~35-65s. Währenddessen ist das Display leer/flackernd.
|
||
- **Ghosting:** Leichtes Ghosting bei manchen Farben normal. Display nicht bei direktem Sonnenlicht ablesen.
|
||
|
||
## Recovery
|
||
|
||
Falls das konfigurierte WLAN nicht erreichbar ist: der Pi startet automatisch einen **Recovery AP**.
|
||
|
||
- **SSID:** `epaper-recovery`
|
||
- **Passwort:** `recovery1234`
|
||
- **URL:** http://10.42.0.1:8080/
|
||
|
||
Dort kannst du ein neues WLAN konfigurieren. Details in `RECOVERY.md`.
|
||
|
||
## Lizenz
|
||
|
||
Apache 2.0
|