MQTT-Display-LaserCutter/Implementation-Plan.md

11 KiB
Raw Blame History

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

  • 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)
  • 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
  • 1.3 Build prüfen (leeres Projekt kompiliert fehlerfrei)

  • 1.4 Test Verdrahtung Dot-Matrix-Display

    • GYMAX7219-Module gemäß Pinbelegung angeschlossen (MOSI GPIO 23, CLK GPIO 18, CS GPIO 5)
    • Hardware-Typ GENERIC_HW (verifiziert; physische 90° Verdrehung per Software CCW kompensiert)
    • Externes 5 V-Netzteil erforderlich (~0,5 A / ~2,5 W gemessen; USB-Port reicht nicht)
    • SPI-Taktrate auf 1 MHz reduziert für stabile Ansteuerung aller 8 Module
    • 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
  • 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)
    • Globale Instanz settings, settings.begin() in main.cpp
  • 2.2 Unit-Test (Serial-Output): Werte schreiben, ESP32 neu starten, Werte lesen und verifizieren

    • test_sketches/test_nvs.cpp erstellt, test-nvs Environment in platformio.ini
    • Round-Trip-Test + Persistenz-Check über Neustart

Phase 3 WiFi & WiFiManager

  • 3.1 WiFiManager einbinden

    • include/wifi_connector.h + src/wifi_connector.cpp erstellt
    • AP-Name: LaserCutter-Setup (aus config.h)
    • Captive-Portal-Seite für WLAN-Credentials
    • Timeout: 120 s, danach ESP.restart()
  • 3.2 Verbindungsstatus-Callback implementieren (für spätere Fehleranzeige)

    • WifiStatusCallback-Typ + onStatusChange() Methode
    • Status-Enum: DISCONNECTED, AP_ACTIVE, CONNECTING, CONNECTED
    • Globale Instanz wifiConnector, wifiConnector.begin() + .loop() in main.cpp
  • 3.3 Test: Erstverbindung mit neuem AP, gespeichertes WLAN nach Neustart automatisch verbinden

    • test_sketches/test_wifi.cpp erstellt, test-wifi Environment in platformio.ini
    • BOOT-Taste (GPIO 0, 3 s) löscht Credentials und erzwingt Portal
    • Erstverbindung via Captive Portal , Auto-Reconnect nach Neustart

Phase 4 Dot-Matrix-Display (DisplayManager)

  • 4.1 include/display_manager.h + src/display_manager.cpp erstellen
    Implementierung mit rohem MD_MAX72XX (nicht MD_Parola) für vollständige Rotationskontrolle:

    • Zone 0 (Module 03, obere Reihe): Laserzeit in Minuten
    • Zone 1 (Module 47, untere Reihe): Countdown / Statusmeldungen
    • rotateCCW() kompensiert physische 90°-CW-Verdrehung der Module
    • 17 Zeichen-Bitmaps definiert (09, Sonderzeichen, Buchstaben)
  • 4.2 Methoden implementiert:

    • showLaserTime(float minutes) obere Zeile (4 Formate je Wertebereich)
    • showCountdown(int seconds) untere Zeile, rechtsbündig (während Gratiszeit)
    • showIdle() -- in unterer Zeile wenn kein Countdown aktiv
    • showStatus(const char* msg) max. 4-Zeichen-Statusmeldung (untere Zeile)
    • setBrightness(), allLedsOn(), allLedsOff(), clear(), printToSerial()
    • update() in loop() aufrufen (no-op, Interface für künftige Animationen)
    • main.cpp integriert: display.begin(), display.showIdle(), display.update()
  • 4.3 Test: test_sketches/test_display_manager.cpp, Environment test-display-mgr

    • Alle LEDs EIN/AUS
    • showLaserTime() alle 12 Grenzwerte (0.0 9999.0 min)
    • showCountdown() 5→0
    • showIdle() --
    • showStatus() mit „Err ", „AP ", „WiFi", „ oF"
    • Realistischer Loop: Laserzeit steigt, Countdown 20→0, dann Idle

Phase 5 Laser-Signaldetektion & Zeit-Tracking (LaserTracker)

  • 5.1 include/laser_tracker.h + src/laser_tracker.cpp erstellt

    • Globale Instanz laserTracker, in main.cpp integriert
  • 5.2 GPIO-Eingang konfiguriert:

    • INPUT_PULLUP auf GPIO 4
    • Software-Debounce 50 ms (LASER_DEBOUNCE_MS aus config.h)
    • Polarität aus settings.get().signalPolarity (LOW_ACTIVE / HIGH_ACTIVE)
  • 5.3 Session-Logik implementiert:

    • onSessionStart() intern → _sessionActive = true, Timer setzen
    • onSessionEnd() intern → Netto-Sekunden berechnen, _totalMinutesBase addieren, NVS via settings.saveTotalMinutes()
  • 5.4 Gratiszeit-Logik:

    • Countdown läuft ab Session-Start
    • getSessionSeconds() gibt erst nach Ablauf der Gratiszeit > 0 zurück
    • getCountdownRemaining() → verbleibende Sekunden (0 wenn abgelaufen / inaktiv)
    • getTotalMinutes() = NVS-Basis + laufende Session-Netto-Minuten (Live-Anzeige)
  • 5.5 Öffentliche Getter:

    • getTotalMinutes() → float (Live)
    • getSessionSeconds() → int (Netto ohne Gratiszeit)
    • getCountdownRemaining() → int (verbleibende Gratiszeit)
    • isActive() → bool
    • getLastSessionSeconds() → int (letzte abgeschlossene Session, für MQTT)
    • resetTotal() → Gesamtzeit auf 0 + NVS-Speicherung
  • 5.6 Test: test_sketches/test_laser_tracker.cpp, Environment test-laser-tracker

    • Button GPIO 4 simuliert Laser-Signal
    • BOOT-Taste (GPIO 0, 3 s) löscht Gesamtzeit
    • Boot-Output: NVS-Werte geladen, Display zeigt Basiswert + Idle
    • Manuelle Verifikation: Button drücken → Countdown, Netto-Zeit, Session-Ende → NVS

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 (TLS automatisch bei Port 8883)

  • 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 publishHeartbeat(totalMin, ipStr, uptimeSec):

    • Topic: lasercutter/status (retained)
    • Heartbeat alle 30 Sekunden
    • LWT {"online":false} bei Verbindungsverlust
  • 6.5 Subscribe auf lasercutter/reset:

    • Payload "1", {"reset":true} oder {"reset":1}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
    ⚠️ Offen: MQTT-Error Modul 5 bei Verbindungsverlust, Reconnect nach WiFi-Ausfall


Phase 7 Webinterface (WebServer)

  • 7.1 include/web_server.h + src/web_server.cpp erstellen
    Basierend auf ESPAsyncWebServer

  • 7.2 Route GET / Statusseite (HTML):

    • Session-Minuten, Gesamtzeit, letzter Burst
    • WLAN-Status (IP), MQTT-Status (verbunden/getrennt)
    • Broker-Info, Gratiszeit
    • Auto-Reload alle 10 s
  • 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)
    Redirect + Hinweis „Neustart für MQTT-Änderungen"

  • 7.5 Route POST /reset Session zurücksetzen (laserTracker.resetSession())
    Gesamtzeit (NVS) bleibt erhalten; Wartungsreset nur per BOOT-Taste oder MQTT

  • 7.6 ElegantOTA unter /update einbinden
    Flag ELEGANTOTA_USE_ASYNC_WEBSERVER=1 in platformio.ini

  • 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: SettingsDisplayManagerWiFiManagerMqttClientWebServerLaserTracker
  • 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 LaserTrackerMqttClient.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