MQTT-Display-LaserCutter/Implementation-Plan.md
MaPaLo76 6ac33f459d feat(phase1): complete hardware setup, display and button test sketches
- platformio.ini: add all 8 libraries via Git URLs, add test-display and
  test-button environments, reduce SPI clock to 1 MHz for stability
- include/config.h: add pin definitions, DISPLAY_HW_TYPE=GENERIC_HW,
  MQTT topics, NVS keys and logging macros
- src/main.cpp: add minimal startup skeleton with config.h include
- test_sketches/test_display.cpp: diagnostic sketch showing 0-based module
  index; GENERIC_HW verified with 90 deg CCW software rotation
- test_sketches/test_button.cpp: GPIO INPUT_PULLUP test; LOW_ACTIVE confirmed
- test_sketches/README.md: add wiring tables, flash commands, results table
- README.md: update HW type to GENERIC_HW, add power supply note (0.5A /
  2.5W measured, external 5V PSU required), add Conventional Commits section
- Implementation-Plan.md: mark tasks 1.1-1.5 as complete

BREAKING CHANGE: none
2026-02-22 13:20:52 +01:00

241 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan Laser Cutter MQTT Display
> Dieses Dokument beschreibt die Entwicklungsreihenfolge des Projekts.
> Tasks werden während der Entwicklung mit `[x]` abgehakt.
---
## Phase 1 Projekt-Setup & Konfiguration
- [x] **1.1** `platformio.ini` mit allen benötigten Bibliotheken erweitern
- `MD_Parola`, `MD_MAX72XX`
- `PubSubClient`
- `WiFiManager` (tzapu/WiFiManager)
- `ESPAsyncWebServer` + `AsyncTCP`
- `ArduinoJson`
- `ElegantOTA`
- `Preferences` (ESP32 built-in, kein Extra-Eintrag nötig)
- [x] **1.2** `include/config.h` erstellen zentrale Pin-Definitionen und Konstanten
- GPIO-Pins (MAX7219 SPI, Laser-Signal)
- Anzahl der Module (8), Zonen-Aufteilung
- Standard-Werte (Gratiszeit 20s, MQTT Port 1883, etc.)
- MQTT-Topic-Konstanten
- [x] **1.3** Build prüfen (leeres Projekt kompiliert fehlerfrei)
- [x] **1.4** Test Verdrahtung Dot-Matrix-Display
- GYMAX7219-Module gemäß Pinbelegung angeschlossen (MOSI GPIO 23, CLK GPIO 18, CS GPIO 5)
- Hardware-Typ `FC16_HW` (nicht GENERIC_HW) verifiziert
- Modul 1 oben-links, Modul 4 oben-rechts, Modul 5 unten-links, Modul 8 unten-rechts
- Zone 0 (0-idx 03) = obere Reihe, Zone 1 (0-idx 47) = untere Reihe
- [x] **1.5** Test Verdrahtung Potentialfreier Schalter (Phase 1: Push Button)
- Push Button an GPIO 4 und GND angeschlossen (INPUT_PULLUP, kein externer Widerstand nötig)
- Pegel verifiziert: Button offen = HIGH, Button gedrückt = LOW → Polarität: LOW_ACTIVE
- Debounce 50 ms funktioniert
---
## Phase 2 NVS Persistenz (`Settings`)
- [ ] **2.1** `include/settings.h` + `src/settings.cpp` erstellen
Speichert und lädt alle Konfigurationswerte über ESP32 `Preferences` (NVS):
- MQTT Broker IP, Port, User, Passwort
- Gratiszeit (0120 s)
- Signal-Polarität (`LOW_ACTIVE` / `HIGH_ACTIVE`)
- Akkumulierte Laserzeit (float, Minuten)
- [ ] **2.2** Unit-Test (Serial-Output): Werte schreiben, ESP32 neu starten, Werte lesen und verifizieren
---
## Phase 3 WiFi & WiFiManager
- [ ] **3.1** WiFiManager einbinden
- AP-Name: `LaserCutter-Setup`
- Captive-Portal-Seite für WLAN-Credentials
- Timeout: 120 s, danach Neustart
- [ ] **3.2** Verbindungsstatus-Callback implementieren (für spätere Fehleranzeige)
- [ ] **3.3** Test: Erstverbindung mit neuem AP, gespeichertes WLAN nach Neustart automatisch verbinden
---
## Phase 4 Dot-Matrix-Display (`DisplayManager`)
- [ ] **4.1** `include/display_manager.h` + `src/display_manager.cpp` erstellen
Wrapper um `MD_Parola` mit zwei Zonen:
- Zone 0 (Module 03, obere Reihe): Laserzeit in Minuten
- Zone 1 (Module 47, untere Reihe): Countdown / Statusmeldungen
- [ ] **4.2** Methoden implementieren:
- `showLaserTime(float minutes)` obere Zeile
- `showCountdown(int seconds)` untere Zeile (während Gratiszeit)
- `showIdle()` `---` in unterer Zeile wenn kein Countdown
- `showError(const char* msg)` Fehlermeldung in unterer Zeile, Modul 1
- `update()` in `loop()` aufrufen (MD_Parola benötigt regelmäßigen Aufruf)
- [ ] **4.3** Test: Statische Zahlen und Scrolltext auf beiden Zonen anzeigen
---
## Phase 5 Laser-Signaldetektion & Zeit-Tracking (`LaserTracker`)
- [ ] **5.1** `include/laser_tracker.h` + `src/laser_tracker.cpp` erstellen
- [ ] **5.2** GPIO-Eingang konfigurieren:
- `INPUT_PULLUP` auf GPIO 4
- Software-Debounce (min. 50 ms Entprellzeit)
- Polarität über `Settings` auslesbar
- [ ] **5.3** Session-Logik implementieren:
- `onLaserActive()` → Session-Start, Timer starten
- `onLaserInactive()` → Session-Ende, akkumulierte Zeit aktualisieren, NVS speichern
- [ ] **5.4** Gratiszeit-Logik:
- Countdown läuft ab Session-Start
- Zeit wird erst nach Ablauf der Gratiszeit zur Gesamtzeit addiert
- `getCountdownRemaining()` → Rückgabe verbleibende Sekunden (0 wenn abgelaufen)
- [ ] **5.5** Öffentliche Getter:
- `getTotalMinutes()` → float
- `getSessionSeconds()` → int (aktuelle Session ohne Gratiszeit)
- `isActive()` → bool
- `getLastSessionSeconds()` → int (für MQTT Publish)
- [ ] **5.6** Test: Laser-Signal simulieren (GPIO auf GND ziehen), Zeitmessung verifizieren
---
## Phase 6 MQTT Client (`MqttClient`)
- [ ] **6.1** `include/mqtt_client.h` + `src/mqtt_client.cpp` erstellen
Wrapper um `PubSubClient`
- [ ] **6.2** Verbindungsaufbau mit Credentials aus `Settings`
- [ ] **6.3** Publish-Methode `publishSession(sessionSec, totalMin, gratisSec)`:
- Topic: `lasercutter/session`
- JSON mit `session_s`, `total_min`, `gratiszeit_s`, `ts`
- Wird von `LaserTracker` beim Session-Ende aufgerufen
- [ ] **6.4** Publish-Methode `publishStatus(totalMin, ipStr, uptimeSec)`:
- Topic: `lasercutter/status`
- Heartbeat alle 60 Sekunden
- QoS 0
- [ ] **6.5** Subscribe auf `lasercutter/reset`:
- Payload `"1"` oder `{"action":"reset"}``LaserTracker::resetTotal()`
- QoS 1
- [ ] **6.6** Reconnect-Logik (Non-blocking, max. alle 10 Sekunden versuchen)
- [ ] **6.7** Test: Session-Daten mit MQTT Explorer empfangen, Reset auslösen und verifizieren
---
## Phase 7 Webinterface (`WebServer`)
- [ ] **7.1** `include/web_server.h` + `src/web_server.cpp` erstellen
Basierend auf `ESPAsyncWebServer`
- [ ] **7.2** Route `GET /` Statusseite (HTML):
- Aktuelle Laserzeit (Minuten)
- Letzter Session-Wert (Sekunden)
- WLAN-Status, MQTT-Status
- IP-Adresse
- [ ] **7.3** Route `GET /config` Konfigurationsformular (HTML):
- MQTT Broker IP, Port, User, Passwort
- Gratiszeit (Slider 0120 s)
- Signal-Polarität (Radio-Button)
- [ ] **7.4** Route `POST /config` Konfiguration speichern (via `Settings`, NVS)
- [ ] **7.5** Route `POST /reset` Laserzeit zurücksetzen (Button auf Statusseite)
- [ ] **7.6** ElegantOTA unter `/update` einbinden
- [ ] **7.7** Test: Alle Seiten im Browser aufrufen, Konfiguration ändern und nach Neustart prüfen
---
## Phase 8 Integration & Hauptprogramm (`main.cpp`)
- [ ] **8.1** `main.cpp` aufräumen und alle Module initialisieren:
- Reihenfolge: `Settings``DisplayManager``WiFiManager``MqttClient``WebServer``LaserTracker`
- [ ] **8.2** `loop()` implementieren:
- `displayManager.update()`
- `laserTracker.update()` (GPIO-Polling + Session-Logik)
- `mqttClient.loop()` (Reconnect + Heartbeat)
- `displayManager.showLaserTime(laserTracker.getTotalMinutes())`
- `displayManager.showCountdown(...)` oder `showIdle()` oder `showError(...)`
- [ ] **8.3** Callback von `LaserTracker``MqttClient.publishSession(...)` verdrahten
- [ ] **8.4** WLAN/MQTT-Fehlerzustand auf Display spiegeln
- [ ] **8.5** Watchdog Timer aktivieren (ESP32 WDT, 30 s)
---
## Phase 9 OTA & Stabilisierung
- [ ] **9.1** ElegantOTA in `main.cpp` initialisieren und in `loop()` einbinden
- [ ] **9.2** Serielles Logging vereinheitlichen (Log-Level: INFO / DEBUG per `#define`)
- [ ] **9.3** Langzeit-Test: 24h Betrieb, Speicherleck-Check via Serial Monitor (`ESP.getFreeHeap()`)
- [ ] **9.4** Edge-Cases testen:
- Laser aktiv, WLAN wird getrennt → Display läuft weiter
- MQTT-Broker nicht erreichbar → Reconnect
- Reset während aktiver Session
- Neustart nach akkumulierter Zeit → Zeit korrekt aus NVS geladen
---
## Phase 10 Dokumentation & Abschluss
- [ ] **10.1** README.md finalisieren (Screenshots, Schaltplan-Skizze ggf. ergänzen)
- [ ] **10.2** `platformio.ini` mit finalen Library-Versionen dokumentieren
- [ ] **10.3** MQTT-Topics in README.md validieren (mit realem Broker testen)
- [ ] **10.4** Optionaler Schaltplan (Fritzing / ASCII) für Laser-Signal-Anschluss (Optokoppler)
---
## Abhängigkeitsdiagramm (Reihenfolge)
```
Phase 1 (Setup)
└── Phase 2 (NVS/Settings)
├── Phase 3 (WiFi)
├── Phase 4 (Display)
└── Phase 5 (LaserTracker)
└── Phase 6 (MQTT)
└── Phase 7 (Webinterface)
└── Phase 8 (Integration)
└── Phase 9 (OTA/Stabilisierung)
└── Phase 10 (Doku)
```
---
## Verwendete MQTT-Topics (Überblick)
| Topic | Richtung | QoS | Auslöser |
|------------------------|-----------|-----|-------------------------------|
| `lasercutter/session` | Publish | 1 | Session-Ende (Laser inaktiv) |
| `lasercutter/status` | Publish | 0 | Heartbeat alle 60 s |
| `lasercutter/reset` | Subscribe | 1 | Externer Reset-Befehl |
---
*Erstellt: 22. Februar 2026*