docs: add README with full architecture and plugin guide

This commit is contained in:
ki
2026-08-26 14:15:21 +04:00
parent 28124c5617
commit 502e4459c3
+146 -46
View File
@@ -1,76 +1,176 @@
# 7.3" ePaper Dashboard
# epaper-dashboard
Plugin-basiertes Dashboard für Waveshare 7.3-inch ACeP 7-Color e-Paper (F) HAT auf einem Raspberry Pi 4.
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.
## 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
- **Renderer (`dashboard.py`)**: Lädt `config.json`, instanziiert Plugins, refresht das Display alle `refresh_interval_s` Sekunden (≥180 empfohlen). Reagiert auf Live-Trigger via Unix-Socket.
- **Web-Admin (`admin.py`)**: HTTP Basic Auth, konfiguriert Slots, Plugins und Secrets im Browser. Triggert Live-Refresh.
- **Plugins (`plugins/`)**: Jedes Widget ist ein Python-Modul mit `Widget`-Klasse (siehe `plugins/base.py`). Eigenes Plugin = eine Datei in `plugins/`.
- **Templates (`templates/index.html`)**: Single-Page-UI, auto-reload-fähig.
## Setup
```bash
# Auf dem Pi:
sudo apt install python3-pil python3-numpy python3-flask git
git clone <dieses repo> # oder rsync von deinem Dev-Rechner
cd port/
# SPI in /boot/firmware/config.txt aktivieren (dtparam=spi=on)
# Reboot
python3 admin.py &
python3 dashboard.py &
```
┌─────────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────────┘
```
Web-UI: <http://pi:8080/>
Default Login: `admin` / `admin` — bitte `EPAPER_ADMIN_PASSWORD` in `.env` setzen.
## Quick Start
## Plugin schreiben
### Pi vorbereiten
Eine Datei `plugins/my_widget.py`:
```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,
"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
- **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 | — |
| `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` |
| `hello` | statisch | `text`, `color`, `size` |
## Eigenes Plugin schreiben
```python
# plugins/my_widget.py
from plugins.base import Widget
from palette import FG, INFO
from palette import FG, BG
class Widget(Widget):
name = "my_widget"
label = "Mein Widget"
description = "Zeigt etwas Nützliches"
description = "Zeigt etwas"
category = "info"
config_schema = [
{"key": "api_key", "label": "API Key", "type": "secret"},
{"key": "interval", "label": "Intervall (Sekunden)", "type": "int", "default": 60},
{"key": "show_extra", "label": "Extra anzeigen", "type": "bool", "default": True},
{"key": "interval", "label": "Intervall (s)", "type": "int", "default": 60},
]
default_config = {"api_key": "", "interval": 60, "show_extra": True}
default_config = {"api_key": "", "interval": 60}
def fetch(self):
# Daten holen (API call, etc.)
return {"value": 42}
def render(self, draw, fonts, x, y, w, h):
# In den Slot zeichnen
d = self.fetch()
draw.text((x + 10, y + 10), f"Value: {d['value']}", font=fonts["28"], fill=FG)
# w, h sind Pixel (nicht Zellen!)
draw.text((x + 10, y + 10), f"Value: {d['value']}",
font=fonts["28"], fill=FG)
```
**Feld-Typen**: `string`, `int`, `float`, `bool`, `secret` (write-only), `select` (mit `choices`), `lat_lon`.
**Palette:** `BLACK, WHITE, RED, GREEN, BLUE, YELLOW, ORANGE` + semantisch `FG, BG, OK, WARN, ALERT, INFO, ACCENT`
**Palette** (aus `palette.py`): `BLACK, WHITE, GREEN, BLUE, RED, YELLOW, ORANGE` + semantisch `FG, BG, OK, WARN, ALERT, INFO, ACCENT`.
## Services
## Mitgelieferte Plugins
```bash
systemctl --user enable --now epaper-dashboard
systemctl --user enable --now epaper-admin
journalctl --user -u epaper-dashboard -f # Logs
```
- `clock` — Uhrzeit / Datum
- `weather` — Open-Meteo Wetter (kein API-Key)
- `system` — Pi CPU/RAM/Uptime
- `hello` — Demo
- `spotify` — Last.fm Scrobble
- `strava` — Strava Aktivitäten
- `gmail` — Gmail Unread
**Wichtig:** `PrivateTmp=no` in den Service-Files — sonst sieht der Admin-Socket `/tmp/epaper-dashboard.sock` nicht.
## Einschränkungen
## Display-Einschränkungen
- **Full Refresh only**: ACeP-Displays vertragen keine schnellen Partial-Refreshes (Verschleiß). Das Hersteller-empfohlene Minimum ist 180s.
- **Kein Live-Websocket**: Snapshot wird per Refresh-Now-Button ausgelöst. Bei Bedarf ergänzbar.
- **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