Konflikt in renderGrid() zwischen HEAD (BUG-01: kein HTML5-draggable, touch-action:none) und BUG-03 (alter draggable=true). Resolution: HEAD-Variante behalten — BUG-01 hat den HTML5-Drag komplett entfernt, BUG-03 nur die Span-Geometrie gefixt. Kompatibel, kein Re-Konflikt. Tests: 5/5 Python + 7/7 Pointer-Events + 8/8 Span-Geometry = alle grün.
epaper-dashboard
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
┌─────────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────────┘
Quick Start
Pi vorbereiten
sudo apt update && sudo apt install -y python3-pil python3-numpy python3-flask git
sudo raspi-config # → Interface Options → SPI → Enable
sudo reboot
Setup
# 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):
{
"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
# plugins/my_widget.py
from plugins.base import Widget
from palette import FG, BG
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!)
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
Services
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