diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..926c667 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,110 @@ +# PLAN – WT32-SC01 Plus Dashboard (Migration von m5stack-dashboard) + +_Letztes Update: 2026-08-02_ + +Referenzprojekt: [skoelle/m5stack-dashboard](https://github.com/skoelle/m5stack-dashboard) (Struktur bekannt, Quelltext-Details noch nicht vollständig eingesehen – siehe Abschnitt 6 „Offene Punkte“). + +Ziel: Neues, eigenständiges Repository `wt32sc01-dashboard`, das fachlich dieselbe Funktionalität liefert wie das M5Stack-Projekt (siehe `SPEC.md`), aber mit Touch-UI im Hochformat auf dem WT32-SC01 Plus. **So viel wie möglich vom bestehenden Code wird übernommen bzw. 1:1 portiert**, nur die Display-/Eingabe-Schicht wird neu gebaut. + +## 1. Migrationsprinzip: Was bleibt, was wird neu gebaut + +Die bestehende Architektur trennt bereits sauber zwischen **Datenschicht** (API-Clients, JSON-Parsing) und **Darstellungsschicht** (Screens, Buttons). Diese Trennung ist der Hebel für die Migration: + +| Modul (Original) | Migrationsstrategie | Begründung | +|---|---|---| +| `src/api/http_client.h/cpp` | **1:1 übernehmen**, ggf. minimal anpassen (Timeout/Retry-Verhalten prüfen) | Reiner HTTP-GET-Wrapper, hardwareunabhängig, gleiche APIs im gleichen Netz | +| `src/api/weather_api.h/cpp` | **1:1 übernehmen** | Reines JSON-Parsing gegen unveränderten Endpoint, keine Display-Abhängigkeit | +| `src/api/calendar_api.h/cpp` | **1:1 übernehmen** | Gleiche Begründung wie Wetter | +| `src/api/departures_api.h/cpp` | **1:1 übernehmen** | Gleiche Begründung wie Wetter | +| `src/icons/icons.h` (RGB565-Bitmaps) | **Teilweise übernehmen, teilweise neu rendern** | Farbkonzept/Symbolik bleibt, aber Icons werden für größeres Display in größerer Auflösung neu exportiert (siehe Task 3) | +| `src/screens/screen_base.h` | **Konzept übernehmen, Implementierung neu** | Abstraktion "Screen mit Lifecycle" bleibt sinnvoll, aber Rendering-API wechselt von M5GFX-Direktzeichnung auf LVGL-Widgets | +| `src/screens/home_screen.h/cpp` | **Fachlogik übernehmen, UI neu bauen** | Datenaufbereitung (welche Werte werden wie angezeigt) bleibt, Layout wird von Button-Screen zu Touch-Kacheln (siehe SPEC.md Abschnitt 5.1) | +| `src/screens/weather_detail_screen.h/cpp` | **Fachlogik übernehmen, UI neu bauen** | Liste wird scrollbar statt starr, Zurück-Button neu (unten links) | +| `src/screens/calendar_detail_screen.h/cpp` | **Fachlogik übernehmen, UI neu bauen** | Gleiche Begründung | +| `src/screens/mvg_screen.h/cpp` | **Fachlogik übernehmen, UI neu bauen** | Gleiche Begründung | +| `src/main.cpp` | **Neu schreiben** | Boot-Flow, Setup/Loop müssen an LVGL-Tick-Handler, Touch-Init und Display-Rotation angepasst werden | +| `platformio.ini` | **Neu schreiben** | Anderes Board (`esp32-s3`), andere Libs (LovyanGFX + LVGL9 statt M5Stack-Lib), andere Build-Flags | +| Button-Navigation (A/B/C) | **Entfällt komplett** | Ersetzt durch Touch-Event-Handler auf Kacheln/Buttons | +| `.gitignore`, `secrets.h.example` | **1:1 übernehmen** | Muster ist hardwareunabhängig | + +**Kurzfassung**: Die komplette `src/api/`-Schicht wandert praktisch unverändert ins neue Repo. Die `src/screens/`-Schicht wird pro Screen in zwei Teile zerlegt: Datenaufbereitung (übernehmen) und Rendering (neu, LVGL-basiert). Nur `main.cpp`, `platformio.ini` und die neue Touch-/Display-Init sind komplett neuer Code. + +## 2. Zielarchitektur (neues Repo) + +``` +wt32sc01-dashboard/ +├── .gitignore (übernommen aus m5stack-dashboard) +├── platformio.ini (neu: esp32-s3, LovyanGFX, LVGL9) +├── include/ +│ ├── secrets.h.example (übernommen) +│ ├── secrets.h (lokal) +│ └── board_pins.h (neu: WT32-SC01-Plus-Pinout) +├── src/ +│ ├── main.cpp (neu) +│ ├── display/ +│ │ └── display_setup.cpp/.h (neu: LovyanGFX-Config, Portrait-Rotation, Touch-Init) +│ ├── api/ (portiert, siehe Abschnitt 1) +│ │ ├── http_client.h/cpp +│ │ ├── weather_api.h/cpp +│ │ ├── calendar_api.h/cpp +│ │ └── departures_api.h/cpp +│ ├── ui/ +│ │ ├── screen_base.h (Konzept portiert, LVGL-Basis neu) +│ │ ├── home_screen.h/cpp (Datenlogik portiert, Kachel-UI neu) +│ │ ├── weather_detail_screen.h/cpp (Datenlogik portiert, Listen-UI neu) +│ │ ├── calendar_detail_screen.h/cpp (Datenlogik portiert, Listen-UI neu) +│ │ ├── mvg_screen.h/cpp (Datenlogik portiert, Listen-UI neu) +│ │ └── widgets/ +│ │ ├── tile_button.h/cpp (neu: wiederverwendbare Touch-Kachel) +│ │ └── back_button.h/cpp (neu: wiederverwendbarer Zurück-Button unten links) +│ └── icons/ +│ └── icons.h (teilweise übernommen, teilweise neu gerendert – siehe Task 3) +├── scripts/ +│ └── deploy.sh (übernommen, ggf. Board-Flag angepasst) +└── README.md (neu, verweist auf Referenzprojekt) +``` + +## 3. Vorgehen in Phasen + +### Phase 0 – Setup +Neues Repo anlegen, Grundgerüst (PlatformIO-Projekt für `esp32-s3`) erstellen, LovyanGFX + LVGL9 als Dependencies einbinden, `.gitignore`/`secrets.h.example` aus Original übernehmen. + +### Phase 1 – Display & Touch zum Laufen bringen +`board_pins.h` mit verifizierter Pinbelegung, `display_setup.cpp` mit LovyanGFX-Panel-Konfiguration (ST7796, 8-Bit-Parallel), Portrait-Rotation erzwingen (320×480), Touch-Treiber (FT6336U) initialisieren, LVGL-Tick/Loop einbinden. Erfolgskriterium: ein einfaches Testrechteck lässt sich per Touch anwählen. + +### Phase 2 – API-Schicht portieren +`src/api/*` unverändert (oder mit minimalen Anpassungen an neue Ordnerstruktur/Includes) ins neue Repo kopieren, gegen die drei bestehenden Endpunkte (Wetter/Kalender/MVG) testen – unabhängig vom UI, z.B. über Serial-Log-Ausgabe verifizieren, dass JSON korrekt geparst wird. + +### Phase 3 – Wiederverwendbare UI-Bausteine +`tile_button` (große antippbare Kachel mit Icon/Titel/Wert) und `back_button` (fixe Position unten links) als LVGL-Komponenten bauen, da beide auf mehreren Screens verwendet werden. + +### Phase 4 – Home-Screen +Wetter-Kachel, Kalender-Kachel (mit 2 Terminen als Vorschau), kleine MVG-Kachel ohne Vorschau; Touch-Handler pro Kachel verlinken auf jeweilige Detailseite; Regen-Hinweis-Badge auf Wetter-Kachel. + +### Phase 5 – Detailseiten +Wetter-Detail (scrollbare Stundenliste), Kalender-Detail (scrollbare 10-Termine-Liste), MVG-Seite (scrollbare Abfahrtsliste) – jeweils mit `back_button` unten links; Fachlogik (Datenaufbereitung/Formatierung) so weit möglich 1:1 aus den Original-Screens übernehmen. + +### Phase 6 – Icons & Feinschliff +Icon-Set aus `icons.h` sichten, für größeres Display ggf. in höherer Auflösung neu exportieren (siehe Task unten), Refresh-Timer (10 Min/1 Min) und 5-Minuten-Inaktivitäts-Rücksprung einbauen, Fehlerzustände (Retry-Icon) auf allen Screens testen. + +### Phase 7 – Deploy & Doku +`deploy.sh` an Board anpassen (ggf. anderer USB-Chip/Baudrate), README schreiben, finale Tests auf echter Hardware, Repo aufräumen. + +## 4. Risiken / Dinge, die beim Portieren zu prüfen sind + +- **M5GFX- vs. LovyanGFX-API-Unterschiede**: Falls die Original-Screens direkt M5GFX-Zeichenbefehle nutzen (statt nur Daten aufzubereiten), lässt sich die UI-Logik nicht 1:1 kopieren, sondern muss pro Screen als LVGL-Widget-Baum neu formuliert werden – die Datenaufbereitung (Strings, Werte, Icon-Auswahl) bleibt aber portierbar. +- **Icon-Format**: RGB565-Arrays aus `icons.h` sind ggf. für 2.0"-Auflösung dimensioniert und müssen für die größere, höher aufgelöste Darstellung auf dem 3.5"-Display neu erzeugt werden (skalieren oder aus Original-Vektoren neu rendern). +- **Speicher/PSRAM**: LVGL-Framebuffer für 320×480 (bzw. Teilbuffer) muss ins PSRAM des ESP32-S3-WROVER gelegt werden – Buffer-Größen in `display_setup.cpp` entsprechend konfigurieren. +- **Pin-Variante**: WT32-SC01-Plus-Board-Revisionen unterscheiden sich leicht in der Pinbelegung – vor Phase 1 anhand des konkreten Boards verifizieren. + +## 5. Nicht-Ziele + +- Kein Rewrite der Backend-APIs (Wetter/Kalender/MVG) – bleiben unverändert. +- Keine Rückwärtskompatibilität zum M5Stack-Repo (kein gemeinsamer Code, kein Git-Submodule/Fork). +- Keine Sprachumschaltung/Mehrsprachigkeit, keine neuen Datenquellen – Funktionsumfang bleibt wie in `SPEC.md` beschrieben. + +## 6. Offene Punkte + +- Der genaue Inhalt von `main.cpp`, den Screen-`.cpp`-Dateien und `icons.h` im Original-Repo konnte technisch noch nicht vollständig ausgelesen werden (GitHub-Tool lieferte bislang nur Dateistruktur/Metadaten, keinen Volltext). Die konkreten Portier-Schritte in Phase 2–6 sollten beim Start der Umsetzung anhand des tatsächlichen Codes verifiziert/verfeinert werden. +- Exakte Pinbelegung des WT32-SC01 Plus (siehe SPEC.md Abschnitt 11). +- Name/Ort des neuen Repositories final bestätigen. diff --git a/README.md b/README.md index 03181e6..2e0200d 100644 --- a/README.md +++ b/README.md @@ -1 +1,77 @@ -# wt32sc01-dashboard +# M5Stack Core Dashboard + +Wetter-, Kalender- und MVG-Abfahrten-Dashboard für den M5Stack Core (ESP32), +gesteuert über die 3 eingebauten Buttons (A, B, C). + +Details zu Funktionsumfang, API-Formaten und Design-Entscheidungen stehen in +`SPEC-final.md` im Space. Umsetzungsschritte stehen in `PLAN.md` und `TODO.md`. + +## Setup + +1. PlatformIO CLI installieren: + ``` + pip install -U platformio + ``` + +2. WLAN-Zugangsdaten eintragen: + ``` + cp include/secrets.h.example include/secrets.h + ``` + Dann in `include/secrets.h` `WIFI_SSID` und `WIFI_PASSWORD` anpassen. + Die drei API-URLs sind bereits vorbefüllt. + +3. Gerät per USB anschließen. + +## Build & Flash + +``` +./scripts/deploy.sh +``` + +Falls mehrere serielle Geräte angeschlossen sind und die automatische +Port-Erkennung fehlschlägt, kann der Port explizit übergeben werden: + +``` +./scripts/deploy.sh /dev/ttyUSB0 +``` + +Das Skript baut nur und flasht, es öffnet keinen seriellen Monitor. + +Falls du den Monitor separat sehen willst: + +``` +pio device monitor +``` + +## Bedienung + +| Button | Funktion | +|---|---| +| A | Wechselt zwischen Wetter-Detail und Kalender-Detail | +| B | Zurück zur Hauptseite | +| C | MVG-Abfahrtsseite | + +Nach 5 Minuten ohne Tastendruck springt das Gerät automatisch zurück zur +Hauptseite. Die Hauptseite aktualisiert sich alle 10 Minuten, die +MVG-Seite jede Minute. + +## Icons + +Die Icons (Sonne, Wolke, Regen, U-/S-Bahn-Badges, Kalender, Fehler-Symbol) +werden aktuell prozedural mit M5Stack-Grafikprimitiven gezeichnet +(`src/icons/icons.h`), um den Flash-Speicher zu schonen. Für echte +Pixel-Art-Bitmaps können die Funktionskörper später durch +`M5.Lcd.drawBitmap(...)`-Aufrufe mit RGB565-Arrays ersetzt werden. + +## Git + +Dieses Projekt ist bewusst noch nicht als Git-Repository initialisiert. +Sobald gewünscht: + +``` +git init +git add . +git commit -m "Initial M5Stack dashboard" +``` + +`include/secrets.h` ist bereits in `.gitignore` ausgeschlossen. diff --git a/SPEC-old.md b/SPEC-old.md new file mode 100644 index 0000000..0f82c0d --- /dev/null +++ b/SPEC-old.md @@ -0,0 +1,239 @@ +# M5Stack Core – Wetter/Kalender/MVG Dashboard + +_Letztes Update: 2026-08-01 23:16 CEST_ + +## 1. Ziel + +Ein M5Stack Core (ESP32, 2.0" IPS Display, 3 physische Buttons: A, B, C) zeigt Wetter, Kalendertermine und MVG-Abfahrten an. Die Navigation erfolgt ausschließlich über die drei Buttons, es gibt keine Touch-Bedienung. Besonderer Fokus liegt auf einer visuell ansprechenden, **farbigen** UI mit eigenen Bitmap-Icons und einem **dunklen Farbschema**, die trotz des kleinen 2.0" Displays hochwertig aussieht. + +## 2. Hardware + +- **Gerät**: M5Stack Core (Basic), ESP32-basiert +- **Display**: 2.0" IPS, 320x240 px +- **Eingabe**: 3 Buttons (A, B, C) +- **Netzwerk**: WLAN (Heimnetz, Zugriff auf `*.fritz.box` Hosts) + +## 3. Toolchain + +- **Build-System**: PlatformIO (kein Arduino IDE) +- **Deployment**: Eigenes Deploy-Skript, das ausschließlich **Build + Flash** durchführt (kein automatisches Öffnen des seriellen Monitors, kein zusätzlicher Schritt danach). USB-Port wird standardmäßig automatisch erkannt (PlatformIO-Standardverhalten), kann aber optional als Parameter/Umgebungsvariable an das Skript übergeben werden, um einen festen Port zu erzwingen (z.B. `./deploy.sh /dev/ttyUSB0`). +- **WLAN-Zugangsdaten**: Fest im Code hinterlegt, aber ausgelagert in eine eigene Datei (z.B. `include/secrets.h` oder `src/secrets.cpp`), die per `.gitignore` vom Git-Repo ausgeschlossen wird. Ein `secrets.h.example` mit Platzhaltern wird stattdessen eingecheckt. +- **Zeitsynchronisation**: Keine eigene NTP-Sync im Gerät. Alle Zeitangaben werden 1:1 so übernommen und dargestellt, wie sie von den APIs geliefert werden (keine relative Umrechnung wie "in 20 Minuten"). +- **Versionskontrolle**: Für den ersten Wurf wird noch kein Git-Repository angelegt bzw. initialisiert (kein `git init`, kein Remote). Die Projektstruktur inkl. `.gitignore` und `secrets.h.example` wird trotzdem von Anfang an sauber vorbereitet, damit später jederzeit unkompliziert `git init` + Remote-Verknüpfung nachgeholt werden kann. + +## 4. Datenquellen (APIs) + +Alle APIs liegen im lokalen Netz und liefern JSON per HTTP GET. + +### 4.1 Wetter-API + +- **Endpoint**: `http://docker-host-pve.fritz.box:3088/api/weather` +- **Methode**: GET +- **Beispiel-Response**: + +```json +{ + "current": { + "temperature": 20, + "symbol": "mo____", + "description": "Klar", + "emoji": "🌙" + }, + "forecast": [ + { + "time": "2026-08-01T23:00:00+02:00", + "temperature": 20, + "symbol": "mb____", + "description": "Bewölkt", + "emoji": "🌙", + "precipitation": { "probability": 0.2, "type": "rain" } + }, + { + "time": "2026-08-02T00:00:00+02:00", + "temperature": 20, + "symbol": "mb____", + "description": "Bewölkt", + "emoji": "🌙", + "precipitation": { "probability": 0.2, "type": "rain" } + } + ] +} +``` + +- `current`: aktuelles Wetter +- `forecast`: stündliche Vorhersage (im Beispiel 8 Einträge), jeder Eintrag enthält u.a. `precipitation.probability` (0.0–1.0) und `precipitation.type` (z.B. `"rain"`) +- `symbol`: interner Wettercode (z.B. `mo____` = klar/Mond, `mb____` = bewölkt/Mond, `wb____` = bewölkt/Tag). Wird als Grundlage für die Auswahl des passenden Bitmap-Icons verwendet (siehe Abschnitt 7) + +### 4.2 Kalender-API + +- **Endpoint**: `http://docker-host-pve.fritz.box:8077/api/events` +- **Methode**: GET +- **Liefert**: die nächsten 10 Termine (bereits chronologisch sortiert, serverseitig limitiert) +- **Beispiel-Response**: + +```json +{ + "events": [ + { + "id": 205, + "summary": "Sommerferien", + "description": "", + "location": "", + "start_at": "2026-08-03T00:00:00", + "end_at": "2026-09-15T00:00:00", + "all_day": true, + "status": "CONFIRMED" + }, + { + "id": 113, + "summary": "Zahnarzt Nepomuk", + "description": "", + "location": "", + "start_at": "2026-08-03T08:00:00", + "end_at": "2026-08-03T09:00:00", + "all_day": false, + "status": "CONFIRMED" + } + ], + "count": 10, + "query_time": "2026-08-01T20:58:37.858934Z" +} +``` + +- Für die Hauptseite werden die ersten 2 Einträge aus `events` verwendet (nächste 2 Termine) +- `all_day` Termine werden anders dargestellt als Termine mit konkreter Uhrzeit (nur Datum statt Uhrzeit) +- Zeiten (`start_at`, `end_at`) werden unverändert übernommen, keine Umrechnung/Lokalisierung + +### 4.3 MVG-Abfahrten-API + +- **Endpoint**: `http://docker-host-pve.fritz.box:8078/api/departures` +- **Methode**: GET +- **Beispiel-Response** (gekürzt): + +```json +{ + "departures": [ + { + "station": "Josephsburg, München", + "type": "UBAHN", + "icon": "U", + "line": "U2", + "destination": "Feldmoching", + "time_epoch": 1785618120, + "time_str": "23:02", + "delay_min": -1, + "cancelled": false, + "messages": [] + }, + { + "station": "Berg am Laim, München", + "type": "SBAHN", + "icon": "S", + "line": "S2", + "destination": "Pasing", + "time_epoch": 1785618840, + "time_str": "23:14", + "delay_min": 4, + "cancelled": false, + "messages": [] + } + ] +} +``` + +- **Kein Filter**: Es werden alle zurückgelieferten Abfahrten (beide Stationen, U-Bahn und S-Bahn gemischt) angezeigt, in der Reihenfolge wie von der API geliefert +- `delay_min`: Verspätung in Minuten (kann negativ sein = früher), `cancelled`: Ausfall-Flag +- `time_str` wird direkt übernommen (keine eigene Zeitberechnung) + +## 5. Screens + +### 5.1 Hauptseite (Home) + +Wird nach Boot standardmäßig angezeigt und ist der "Ruhezustand" des Geräts. + +Inhalt: +- Aktuelle Temperatur + Icon + Beschreibung (aus `current`) +- Regen-Hinweis (weicher Schwellwert): Sobald irgendein Eintrag der nächsten 8 Vorhersage-Stunden `precipitation.type == "rain"` mit `probability > 0` enthält, wird ein Regen-Hinweis-Icon/Banner angezeigt. Es wird also lieber zu früh als zu spät gewarnt. +- Nächste 2 Kalendertermine (Summary + Datum/Uhrzeit, `all_day` gesondert markiert) + +Refresh: alle 10 Minuten (Wetter + Kalender neu abrufen) + +### 5.2 Wetter-Detailseite + +Inhalt: +- Aktuelles Wetter (ausführlicher als Home) +- Stundenweise Vorhersage aus `forecast` (Zeit, Temperatur, Icon, Regenwahrscheinlichkeit) mit Icons statt Text wo sinnvoll + +### 5.3 Kalender-Detailseite + +Inhalt: +- Liste aller 10 Termine aus `events` (nicht nur die ersten 2 wie auf der Hauptseite) + +### 5.4 MVG-Abfahrtsseite + +Inhalt: +- Liste aller Abfahrten aus `departures`, ohne Filterung nach Station oder Linie (Linie, Ziel, Zeit, Verspätung, ggf. Ausfall-Hinweis) + +Refresh: jede Minute + +## 6. Navigation (Buttons) + +| Button | Funktion | +|---|---| +| A | Wechselt zwischen den Detailseiten Wetter und Kalender (Toggle) | +| B | Springt zurück zur Hauptseite | +| C | Öffnet die MVG-Abfahrtsseite | + +- Automatischer Rücksprung zur Hauptseite nach 5 Minuten Inaktivität (kein Button-Druck), unabhängig davon, auf welcher Seite man sich gerade befindet + +## 7. UI- und Icon-Konzept + +Ein zentraler Bestandteil des Projekts ist eine hochwertige, **farbige** und für das kleine Display optimierte Oberfläche, kein reiner Text-Dump. + +- **Farbschema "iPhone Dark Mode"-Look**: Primär reines/sehr dunkles Schwarz (`#000000` bzw. `#0B0B0D`-ähnlich) als Hintergrund mit weißem bzw. sehr hellem Text (`#FFFFFF` / `#F2F2F7`) als Basis, ganz im Stil von iOS Dark Mode. Farbe wird bewusst zurückhaltend und dezent als Akzent eingesetzt (z.B. gedämpfte Blau-/Grüntöne für Wetter, eigene dezente Akzentfarbe für Kalender, an echte MVV-Linienfarben angelehnte, aber nicht grelle Töne für U-Bahn/S-Bahn), nicht als große flächige Buntheit +- **Eigene farbige Bitmap-Icons** statt Unicode-Emojis (M5Stack-Displays unterstützen keine nativen Emoji-Fonts). Icons werden als eingebettete Bitmaps (RGB565-Arrays) im Code hinterlegt, nicht als Dateien auf SD-Karte, um Ladezeiten zu vermeiden +- **Icon-Set mindestens für**: Sonne/klar, bewölkt, Regen, Nacht-Varianten (basierend auf dem `symbol`-Feld, z.B. `mo____`, `mb____`, `wb____`), U-Bahn-Symbol, S-Bahn-Symbol, Kalender-Symbol, Warn-/Regen-Hinweis-Symbol, Retry-/Fehler-Symbol – alle farbig statt monochrom +- **Layout-Prinzipien**: Klare visuelle Hierarchie (große Temperatur, kleinere Nebeninfos), hoher Kontrast durch schwarz/weiß als Basis, moderne, aufgeräumte, iOS-inspirierte Optik ohne überladene Screens, dezente Akzentfarben statt vieler bunter Flächen +- **Typografie**: Angepasste, gut lesbare, weiße Schriftgrößen für das 320x240 Display vor schwarzem Hintergrund, wichtige Werte (Temperatur, Abfahrtszeit) deutlich größer und ggf. fett gegenüber Nebeninfos, ganz im Stil moderner iOS-Widgets + +## 8. Fehlerbehandlung + +- Bei nicht erreichbarer API: Einfache Fehleranzeige auf dem betroffenen Screen (z.B. Retry-Icon + kurzer Text wie "Keine Verbindung") +- **Retry-Auslöser**: Automatisch beim nächsten regulären Refresh-Intervall der jeweiligen Seite (10 Minuten bzw. 1 Minute), zusätzlich manuell durch erneuten Tastendruck auf den Button, der die aktuelle Seite aufruft +- Kein Vorhalten "letzter bekannter Werte" über den Fehlerzustand hinaus gefordert, es genügt die einfache Fehleranzeige bis zum nächsten erfolgreichen Refresh + +## 9. Refresh-Intervalle + +| Seite/Datenquelle | Intervall | +|---|---| +| Hauptseite (Wetter + Kalender) | 10 Minuten | +| MVG-Abfahrtsseite | 1 Minute | +| Wetter-Detailseite | folgt Hauptseiten-Intervall (10 Minuten), da gleiche Datenquelle | +| Kalender-Detailseite | folgt Hauptseiten-Intervall (10 Minuten), da gleiche Datenquelle | + +## 10. Projektstruktur (PlatformIO) + +Git-Initialisierung und Remote-Verknüpfung erfolgen bewusst zu einem späteren Zeitpunkt, nicht in diesem ersten Schritt. Die Ordnerstruktur wird aber von Anfang an git-freundlich vorbereitet: + +``` +/ +├── .gitignore (schließt u.a. include/secrets.h, .pio/ aus – bereits vorbereitet für späteres git init) +├── platformio.ini +├── include/ +│ ├── secrets.h.example (Platzhalter für WLAN, später einzuchecken) +│ └── secrets.h (lokal, später nicht einzuchecken) +├── src/ +│ ├── main.cpp +│ ├── screens/ (Home, WeatherDetail, CalendarDetail, MVG) +│ ├── api/ (HTTP-Clients für Weather, Calendar, MVG) +│ └── icons/ (farbige Bitmap-Icon-Definitionen, RGB565) +├── scripts/ +│ └── deploy.sh (Build + Flash via PlatformIO CLI, USB-Port automatisch erkannt oder optional als Parameter übergeben, kein Monitor) +└── README.md +``` + +- `deploy.sh` ruft im Kern `pio run --target upload` auf; ohne Parameter wird der Port automatisch erkannt, mit Parameter (z.B. `./deploy.sh /dev/ttyUSB0`) wird ein fester Port erzwungen. Kein automatisches Starten des seriellen Monitors oder weiterer Schritte danach. + +## 11. Offene Punkte / Rückfragen + +Aktuell keine offenen Punkte mehr, alle wesentlichen Entscheidungen (Toolchain, UI-Stil, Farbschema, Git-Timing, USB-Port-Handling) sind getroffen. Git-Initialisierung und Remote-Repo werden bewusst erst in einem späteren Schritt nachgeholt, sobald der Code lokal funktioniert. diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 0000000..3dc410f --- /dev/null +++ b/SPEC.md @@ -0,0 +1,158 @@ +# WT32-SC01 Plus – Wetter/Kalender/MVG Dashboard (Touch) + +_Letztes Update: 2026-08-02_ + +## 1. Ziel + +Ein WT32-SC01 Plus (ESP32-S3, 3.5" kapazitiver Touch-IPS-Display) zeigt Wetter, Kalendertermine und MVG-Abfahrten an – funktional analog zum bestehenden [M5Stack-Dashboard](https://github.com/skoelle/m5stack-dashboard), aber als **eigenständiges, komplett neu geschriebenes Projekt** in einem **neuen, eigenen Git-Repository**. Es wird kein Code aus dem M5Stack-Projekt übernommen; lediglich das UI-/API-Konzept und die Backend-Endpunkte werden wiederverwendet. + +Kernunterschiede zum M5Stack: + +- **Touch statt Buttons**: Navigation ausschließlich über Touch-Buttons auf dem Screen, keine physischen Tasten. +- **Deutlich größeres Display** (3.5" statt 2.0"), dadurch großzügigere, besser lesbare Darstellung von Listen (Abfahrten, Termine, Stundenvorhersage). +- **Hochformat (Portrait)** statt Querformat, damit sich Listen (MVG-Abfahrten, Termine, stündliche Vorhersage) besser vertikal darstellen lassen. +- **Home-Screen als Buttons/Kacheln**: Wetter- und Kalenderbereich sind selbst antippbare Kacheln, die direkt zur jeweiligen Detailseite führen (kein separater Toggle-Button nötig). + +## 2. Hardware + +- **Gerät**: WT32-SC01 Plus, ESP32-S3-WROVER (Dual-Core Xtensa LX7, PSRAM) +- **Display**: 3.5" IPS, Treiber-IC ST7796UI, physische Auflösung 480×320 (Querformat ab Werk), Ansteuerung über 8-Bit-Parallel-Interface (i80/8080) +- **Software-Orientierung**: Hochformat (Portrait) → logische Auflösung **320×480** (Breite × Höhe), per Display-Rotation im Code erzwungen +- **Touch**: Kapazitiver Touchcontroller FT6336U, I2C, Single-Touch ausreichend für diese App +- **Sonstige Peripherie am Board**: Lautsprecher, SD-Karte, RS485 – werden für dieses Projekt nicht benötigt +- **Netzwerk**: WLAN (Heimnetz, Zugriff auf `*.fritz.box` Hosts, gleiches Netz wie M5Stack) + +> Hinweis: Pinbelegung (Display-Datenleitungen, Touch-I2C, Backlight, Reset) ist je nach Board-Revision leicht unterschiedlich dokumentiert und wird beim Projektstart anhand des konkret vorliegenden Boards verifiziert und in einer eigenen `board_pins.h` fixiert. + +## 3. Toolchain + +- **Build-System**: PlatformIO (kein Arduino IDE), analog zum M5Stack-Projekt +- **Grafik-Stack**: LovyanGFX als Display-/Touch-Treiber in Kombination mit LVGL (Version 9) für UI-Widgets, Touch-Buttons, Listen und Scroll-Verhalten – bewährte Kombination für das WT32-SC01 Plus +- **Deployment**: Eigenes Deploy-Skript `scripts/deploy.sh`, das ausschließlich **Build + Flash** durchführt (kein automatisches Öffnen des seriellen Monitors, kein Zusatzschritt danach). USB-Port wird standardmäßig automatisch erkannt, kann aber optional als Parameter übergeben werden (z.B. `./deploy.sh /dev/ttyUSB0`) +- **WLAN-Zugangsdaten**: Fest im Code, ausgelagert in `include/secrets.h`, per `.gitignore` vom Repo ausgeschlossen. Ein `secrets.h.example` mit Platzhaltern wird eingecheckt +- **Zeitsynchronisation**: Keine eigene NTP-Sync im Gerät. Alle Zeitangaben werden 1:1 so übernommen und dargestellt, wie sie von den APIs geliefert werden (keine relative Umrechnung wie "in 20 Minuten") +- **Versionskontrolle**: Es wird von Anfang an ein **neues, eigenes Git-Repository** angelegt (`git init` + eigener Remote, z.B. `wt32sc01-dashboard`). Kein Fork und kein geteilter Code mit dem M5Stack-Repo – lediglich als Referenz/Vorbild verlinkt + +## 4. Datenquellen (APIs) + +Identisch zum M5Stack-Projekt, gleiche Backend-Services im lokalen Netz, JSON per HTTP GET. Response-Formate werden **1:1 übernommen**, keine Änderungen am Backend nötig. + +### 4.1 Wetter-API + +- **Endpoint**: `http://docker-host-pve.fritz.box:3088/api/weather` +- Liefert `current` (aktuelles Wetter: `temperature`, `symbol`, `description`, `emoji`) und `forecast` (stündliche Vorhersage inkl. `precipitation.probability` und `precipitation.type`) +- `symbol` (z.B. `mo____`, `mb____`, `wb____`) ist Basis für die Icon-Auswahl + +### 4.2 Kalender-API + +- **Endpoint**: `http://docker-host-pve.fritz.box:8077/api/events` +- Liefert die nächsten 10 Termine, serverseitig chronologisch sortiert (`summary`, `start_at`, `end_at`, `all_day`, `status`, u.a.) +- Für den Home-Screen werden die ersten 2 Einträge verwendet, für die Detailseite alle 10 +- `all_day`-Termine werden anders dargestellt (nur Datum statt Uhrzeit); Zeiten werden unverändert übernommen + +### 4.3 MVG-Abfahrten-API + +- **Endpoint**: `http://docker-host-pve.fritz.box:8078/api/departures` +- Liefert eine ungefilterte Liste aller Abfahrten (beide Stationen, U-Bahn/S-Bahn gemischt, Reihenfolge wie geliefert): `station`, `type`, `icon`, `line`, `destination`, `time_str`, `delay_min`, `cancelled`, `messages` +- `time_str` wird direkt übernommen, keine eigene Zeitberechnung + +## 5. Screens (Hochformat, 320×480) + +### 5.1 Hauptseite (Home) + +Ruhezustand nach Boot. Besteht aus großen, antippbaren **Kacheln/Touch-Buttons**, angeordnet untereinander (Portrait-Layout), im Kachel-Stil ähnlich der Referenzoptik (siehe Abschnitt 7): + +- **Wetter-Kachel** (groß, oben): aktuelle Temperatur, Icon, Beschreibung, ggf. Regen-Hinweis-Badge. Antippen → Wetter-Detailseite +- **Kalender-Kachel** (groß, darunter): zeigt die nächsten 2 Termine (Summary + Datum/Uhrzeit, `all_day` gesondert markiert) direkt auf der Kachel als Vorschau. Antippen → Kalender-Detailseite +- **MVG-Kachel** (klein, unten, **ohne** Abfahrten-Vorschau – nur Icon/Label "MVG" bzw. "Abfahrten"): Antippen → MVG-Abfahrtsseite + +Regen-Hinweis (weicher Schwellwert): Sobald irgendein Eintrag der nächsten 8 Vorhersage-Stunden `precipitation.type == "rain"` mit `probability > 0` enthält, erscheint ein Regen-Hinweis-Icon/Badge auf der Wetter-Kachel. + +Refresh: alle 10 Minuten (Wetter + Kalender neu abrufen) + +### 5.2 Wetter-Detailseite + +- Aktuelles Wetter ausführlicher als auf der Home-Kachel +- Stundenweise Vorhersage aus `forecast` als vertikal scrollbare Liste (Zeit, Temperatur, Icon, Regenwahrscheinlichkeit) – dank Portrait-Format und größerem Display deutlich übersichtlicher als auf dem M5Stack +- **Zurück-Button unten links** → zurück zur Hauptseite + +### 5.3 Kalender-Detailseite + +- Liste aller 10 Termine aus `events` als vertikal scrollbare Liste (nicht nur die ersten 2 wie auf der Home-Kachel) +- **Zurück-Button unten links** → zurück zur Hauptseite + +### 5.4 MVG-Abfahrtsseite + +- Liste aller Abfahrten aus `departures`, ohne Filterung nach Station oder Linie, als vertikal scrollbare Liste (Linie, Ziel, Zeit, Verspätung, ggf. Ausfall-Hinweis) +- **Zurück-Button unten links** → zurück zur Hauptseite + +Refresh: jede Minute + +## 6. Navigation (Touch) + +Keine physischen Buttons – ausschließlich Touch-Bedienung: + +| Aktion | Funktion | +|---|---| +| Tap auf Wetter-Kachel (Home) | Öffnet Wetter-Detailseite | +| Tap auf Kalender-Kachel (Home) | Öffnet Kalender-Detailseite | +| Tap auf MVG-Kachel (Home) | Öffnet MVG-Abfahrtsseite | +| Tap auf Zurück-Button (unten links, auf jeder Detailseite) | Zurück zur Hauptseite | + +Zusätzlich: Automatischer Rücksprung zur Hauptseite nach 5 Minuten Inaktivität (keine Touch-Eingabe), unabhängig davon, auf welcher Seite man sich gerade befindet. + +## 7. UI- und Icon-Konzept + +Gleiches Grundprinzip wie beim M5Stack (hochwertig, farbig, dunkles Farbschema), zusätzlich angelehnt an die im Referenzbild gezeigte **Kachel-Optik** (große, abgerundete Rechtecke mit Icon + Label + kleinem Zusatzwert), übertragen auf ein Hochformat-Dashboard: + +- **Farbschema "iPhone Dark Mode"-Look**: Sehr dunkles Schwarz (`#000000`/`#0B0B0D`) als Hintergrund, weißer/heller Text (`#FFFFFF`/`#F2F2F7`) als Basis. Jede Home-Kachel bekommt einen eigenen, dezenten Akzentton als Kachel-Hintergrund (z.B. gedämpftes Blau für Wetter, eigene Akzentfarbe für Kalender, an MVV-Linienfarben angelehnte Töne für MVG), ähnlich den farbigen Funktionskacheln im Referenzbild, aber ruhiger/dunkler +- **Größere, touch-taugliche Kacheln**: Mindestgröße der Home-Kacheln so bemessen, dass sie bequem mit dem Finger treffbar sind (Richtwert ≥ 80–100 px Höhe bei 320 px Breite); Zurück-Button ebenfalls als große, gut treffbare Fläche unten links +- **Eigene farbige Bitmap-Icons** statt Unicode-Emojis, als eingebettete RGB565-Bitmaps im Code (kein Nachladen von SD-Karte), Icon-Set: Sonne/klar, bewölkt, Regen, Nacht-Varianten (Basis: `symbol`-Feld), U-Bahn-Symbol, S-Bahn-Symbol, Kalender-Symbol, Regen-Hinweis-Symbol, Zurück-Pfeil, Retry-/Fehler-Symbol +- **Layout-Prinzipien**: Klare visuelle Hierarchie (große Temperatur/Uhrzeit, kleinere Nebeninfos), hoher Kontrast schwarz/weiß als Basis, großzügiger als beim M5Stack dank 3.5"-Display und Portrait-Ausrichtung, dezente Akzentfarben statt vieler bunter Flächen +- **Typografie**: Deutlich größere, gut lesbare Schriftgrößen als beim M5Stack (mehr Platz vorhanden), wichtige Werte (Temperatur, Abfahrtszeit) groß und fett gegenüber Nebeninfos + +## 8. Fehlerbehandlung + +- Bei nicht erreichbarer API: Einfache Fehleranzeige auf dem betroffenen Screen bzw. der betroffenen Kachel (Retry-Icon + kurzer Text wie "Keine Verbindung") +- **Retry-Auslöser**: Automatisch beim nächsten regulären Refresh-Intervall, zusätzlich manuell durch erneuten Tap auf die betroffene Kachel bzw. durch Zurück- und wieder-Reinnavigieren in den Screen +- Kein Vorhalten "letzter bekannter Werte" über den Fehlerzustand hinaus gefordert + +## 9. Refresh-Intervalle + +| Seite/Datenquelle | Intervall | +|---|---| +| Hauptseite (Wetter + Kalender) | 10 Minuten | +| MVG-Abfahrtsseite | 1 Minute | +| Wetter-Detailseite | folgt Hauptseiten-Intervall (10 Minuten), da gleiche Datenquelle | +| Kalender-Detailseite | folgt Hauptseiten-Intervall (10 Minuten), da gleiche Datenquelle | + +## 10. Projektstruktur (PlatformIO, neues Repository) + +Eigenständiges, neues Git-Repository (z.B. `wt32sc01-dashboard`), von Anfang an mit `git init` + eigenem Remote, komplett unabhängig vom M5Stack-Repo: + +``` +/ +├── .git/ (eigenes, neues Repository – kein Fork) +├── .gitignore (schließt u.a. include/secrets.h, .pio/ aus) +├── platformio.ini (Board: esp32-s3, LovyanGFX + LVGL9 als Dependencies) +├── include/ +│ ├── secrets.h.example (Platzhalter für WLAN) +│ ├── secrets.h (lokal, nicht eingecheckt) +│ └── board_pins.h (Display-/Touch-Pinbelegung für WT32-SC01 Plus) +├── src/ +│ ├── main.cpp +│ ├── display/ (LovyanGFX-Setup, Rotation/Portrait-Konfiguration) +│ ├── ui/ (LVGL-Screens: Home, WeatherDetail, CalendarDetail, MVG; Kachel-/Button-Widgets) +│ ├── api/ (HTTP-Clients für Weather, Calendar, MVG – eigenständig implementiert) +│ └── icons/ (farbige Bitmap-Icon-Definitionen, RGB565) +├── scripts/ +│ └── deploy.sh (Build + Flash via PlatformIO CLI, kein Monitor) +└── README.md (verweist als Referenz auf https://github.com/skoelle/m5stack-dashboard) +``` + +- `deploy.sh` ruft im Kern `pio run --target upload` auf; ohne Parameter automatische Port-Erkennung, mit Parameter (z.B. `./deploy.sh /dev/ttyUSB0`) fester Port. Kein automatisches Starten des seriellen Monitors + +## 11. Offene Punkte / Rückfragen + +- Exakte Pinbelegung (Display-Datenbus, Touch-I2C-Pins, Backlight) muss anhand des konkret vorliegenden WT32-SC01-Plus-Boards verifiziert werden (Board-Revisionen unterscheiden sich in der Dokumentation leicht) +- Name des neuen GitHub-Repositories ist noch final zu bestätigen (Vorschlag: `wt32sc01-dashboard`) diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..5a6cc22 --- /dev/null +++ b/TODO.md @@ -0,0 +1,76 @@ +# TODO – WT32-SC01 Plus Dashboard + +_Letztes Update: 2026-08-02_ · Details/Begründungen siehe `PLAN.md`, Fachanforderungen siehe `SPEC.md` + +## Phase 0 – Setup + +- [ ] Neues GitHub-Repository anlegen (Vorschlag: `wt32sc01-dashboard`) +- [ ] `git init` lokal, Remote verknüpfen, erster Commit (leeres PlatformIO-Grundgerüst) +- [ ] `platformio.ini` neu anlegen: Board `esp32-s3`, Framework `arduino`, PSRAM aktivieren +- [ ] LovyanGFX und LVGL (v9) als Lib-Dependencies eintragen +- [ ] `.gitignore` aus `m5stack-dashboard` übernehmen (inkl. `include/secrets.h`, `.pio/`) +- [ ] `include/secrets.h.example` aus Original übernehmen, `include/secrets.h` lokal anlegen (nicht committen) + +## Phase 1 – Display & Touch + +- [ ] Exakte Pinbelegung des konkret vorliegenden WT32-SC01-Plus-Boards verifizieren (Display-Datenbus, WR/RD/DC/CS/RST, Backlight, Touch-I2C SDA/SCL/INT) +- [ ] `include/board_pins.h` mit verifizierten Pin-Defines anlegen +- [ ] `src/display/display_setup.cpp/.h`: LovyanGFX-Panel-Konfiguration für ST7796 (8-Bit-Parallel/i80) erstellen +- [ ] Display-Rotation auf Portrait (320×480) erzwingen +- [ ] Touchcontroller FT6336U initialisieren (I2C) und in LVGL als Input-Device registrieren +- [ ] LVGL-Tick-Timer (`lv_tick_inc`) und Haupt-Loop (`lv_timer_handler`) einbauen +- [ ] Testscreen mit einem einzelnen antippbaren Button bauen, Touch-Koordinaten/Kalibrierung verifizieren + +## Phase 2 – API-Schicht portieren + +- [ ] `src/api/http_client.h/cpp` aus Original-Repo in neues Repo kopieren, Includes/Namespaces anpassen +- [ ] `src/api/weather_api.h/cpp` kopieren, gegen Endpoint `http://docker-host-pve.fritz.box:3088/api/weather` testen +- [ ] `src/api/calendar_api.h/cpp` kopieren, gegen Endpoint `http://docker-host-pve.fritz.box:8077/api/events` testen +- [ ] `src/api/departures_api.h/cpp` kopieren, gegen Endpoint `http://docker-host-pve.fritz.box:8078/api/departures` testen +- [ ] Alle drei API-Clients unabhängig vom UI verifizieren (Serial-Log: Parsing korrekt, Felder vollständig) +- [ ] WLAN-Verbindungsaufbau (Setup-Routine) aus Original übernehmen/anpassen + +## Phase 3 – Wiederverwendbare UI-Bausteine + +- [ ] `src/ui/widgets/tile_button.h/cpp`: LVGL-Kachel-Komponente (Icon + Titel + optionaler Wert/Vorschau-Text), touch-tauglich groß dimensioniert +- [ ] `src/ui/widgets/back_button.h/cpp`: fixer Zurück-Button unten links, auf allen Detailseiten wiederverwendbar +- [ ] Gemeinsames Farbschema/Theme (Dark Mode, Akzentfarben pro Kategorie) als LVGL-Style-Konstanten definieren +- [ ] `src/ui/screen_base.h`: gemeinsame Screen-Lifecycle-Abstraktion (create/show/hide/refresh) für LVGL + +## Phase 4 – Home-Screen + +- [ ] `src/ui/home_screen.h/cpp`: Layout mit Wetter-Kachel (groß, oben), Kalender-Kachel (groß, mit 2 Terminen), MVG-Kachel (klein, ohne Vorschau) +- [ ] Fachlogik aus Original `home_screen.cpp` übernehmen: Temperatur/Icon/Beschreibung-Aufbereitung, Regen-Hinweis-Schwellwert-Logik, Termin-Formatierung (`all_day` vs. Uhrzeit) +- [ ] Touch-Handler: Tap auf Wetter-Kachel → Wetter-Detail, Tap auf Kalender-Kachel → Kalender-Detail, Tap auf MVG-Kachel → MVG-Seite +- [ ] Regen-Hinweis-Badge auf Wetter-Kachel einbauen +- [ ] Refresh-Timer 10 Minuten (Wetter + Kalender) einbauen + +## Phase 5 – Detailseiten + +- [ ] `src/ui/weather_detail_screen.h/cpp`: scrollbare Stundenliste (Zeit, Temperatur, Icon, Regenwahrscheinlichkeit), Fachlogik aus Original übernehmen +- [ ] `src/ui/calendar_detail_screen.h/cpp`: scrollbare Liste aller 10 Termine, Fachlogik aus Original übernehmen +- [ ] `src/ui/mvg_screen.h/cpp`: scrollbare Liste aller Abfahrten (Linie, Ziel, Zeit, Verspätung, Ausfall-Hinweis), Fachlogik aus Original übernehmen +- [ ] `back_button`-Widget auf allen drei Detailseiten unten links einbinden und verdrahten +- [ ] Refresh-Timer 1 Minute für MVG-Seite einbauen + +## Phase 6 – Icons & Feinschliff + +- [ ] `icons.h` aus Original sichten: welche Icons sind direkt übernehmbar, welche müssen in höherer Auflösung neu exportiert werden +- [ ] Fehlende/größere Icon-Varianten neu rendern (RGB565-Arrays), Icon-Set vervollständigen (inkl. Zurück-Pfeil-Icon, das es im Original nicht gab) +- [ ] 5-Minuten-Inaktivitäts-Timer (automatischer Rücksprung zur Hauptseite) implementieren +- [ ] Fehlerzustände (API nicht erreichbar) auf allen Screens mit Retry-Icon/Text umsetzen, manueller Retry per Tap +- [ ] Visuelle Feinabstimmung: Schriftgrößen, Abstände, Kachel-Farben gegen Referenzbild/SPEC.md prüfen + +## Phase 7 – Deploy & Doku + +- [ ] `scripts/deploy.sh` aus Original übernehmen, Board-Flag/Baudrate für WT32-SC01 Plus anpassen +- [ ] Testen: Build + Flash über `deploy.sh` ohne Parameter (Auto-Port) und mit explizitem Port +- [ ] `README.md` schreiben (Setup-Anleitung, Verweis auf `m5stack-dashboard` als Referenzprojekt) +- [ ] End-to-End-Test auf echter Hardware: alle 4 Screens, alle Touch-Interaktionen, beide Refresh-Intervalle, Inaktivitäts-Rücksprung, Fehlerfall (WLAN/API trennen) +- [ ] Repo aufräumen (nicht benötigte PlatformIO-Boilerplate entfernen), finalen Commit/Tag setzen + +## Blocker / braucht Klärung + +- [ ] Original-Quelltext (`main.cpp`, Screen-`.cpp`-Dateien, `icons.h`) muss noch im Detail eingesehen werden (GitHub-Tool lieferte bisher nur Struktur, keinen Volltext) – vor Phase 2/4/5/6 nachholen, um exakte Portier-Aufwände zu bestätigen +- [ ] Pinbelegung WT32-SC01 Plus am konkreten Board verifizieren (Blocker für Phase 1) +- [ ] Name des neuen Repositories final bestätigen