Laser Cutter Dot Matrix Display und MQTT Client
Go to file
MaPaLo76 26a4e9b95c fix(display): redesign module layout - integer minutes, dedicated error slots
New module assignment:
  Module 0       : WiFi error indicator (showWifiError) - 'W' / blank
  Module 1-3     : laser time in full minutes, 3-digit right-aligned
  Module 4       : MQTT error indicator (showMqttError) - 'M' / blank
  Module 5-7     : countdown seconds / idle / status, 3-digit right-aligned

Changes in display_manager.h:
- Update zone layout comments
- showLaserTime: integer minutes only, writes modules 1-3 (module 0 untouched)
- showCountdown: writes modules 5-7 only (module 4 untouched)
- showIdle: ' --' on modules 5-7
- showStatus: 3-char string on modules 5-7
- Add showWifiError(bool): module 0
- Add showMqttError(bool): module 4

Changes in display_manager.cpp:
- Add BMP_M character bitmap
- Add 'M' case in charBitmap()
- Rewrite showLaserTime() - round to int, 3 chars, modules 1-3
- Rewrite showCountdown() - 3 chars, modules 5-7
- Rewrite showIdle() - ' --' on modules 5-7
- Rewrite showStatus() - 3 chars, modules 5-7
- Add showWifiError() / showMqttError() implementations
- Update printToSerial() log output

Changes in test_sketch:
- 9 test steps covering all new methods incl. combination test
- Tested on hardware: all steps passed
2026-02-22 14:15:18 +01:00
.vscode Initial Version of README.md 2026-02-22 10:34:37 +01:00
doc fix(display): redesign module layout - integer minutes, dedicated error slots 2026-02-22 14:15:18 +01:00
include fix(display): redesign module layout - integer minutes, dedicated error slots 2026-02-22 14:15:18 +01:00
lib Initial Version of README.md 2026-02-22 10:34:37 +01:00
parser 1. Vorschlag Implementierung 2026-02-22 11:13:16 +01:00
src fix(display): redesign module layout - integer minutes, dedicated error slots 2026-02-22 14:15:18 +01:00
test Initial Version of README.md 2026-02-22 10:34:37 +01:00
test_sketches fix(display): redesign module layout - integer minutes, dedicated error slots 2026-02-22 14:15:18 +01:00
.gitignore Initial Version of README.md 2026-02-22 10:34:37 +01:00
Implementation-Plan.md feat(display): implement DisplayManager with raw MD_MAX72XX 2026-02-22 14:00:54 +01:00
platformio.ini feat(display): implement DisplayManager with raw MD_MAX72XX 2026-02-22 14:00:54 +01:00
README.md feat(phase1): complete hardware setup, display and button test sketches 2026-02-22 13:20:52 +01:00

Laser Cutter Dot Matrix Display und MQTT Client

Dieses Projekt implementiert einen ESP32-basierten MQTT-Client mit Dot-Matrix-Display für einen Laser Cutter. Es misst und visualisiert die aktive Laserzeit, sendet Session-Daten an einen MQTT-Broker und bietet ein Browser-Webinterface zur Konfiguration und Steuerung.


Inhaltsverzeichnis

  1. Hardware
  2. Pinbelegung
  3. Display
  4. Laser-Signaldetektion
  5. Zeit-Tracking & Gratiszeit
  6. MQTT Client
  7. Webinterface
  8. Konfiguration & Persistenz
  9. WiFi-Setup (WiFiManager)
  10. OTA Firmware-Update
  11. Fehlerverhalten
  12. Bibliotheken
  13. Build & Flash
  14. Beitragen / Commits

Hardware

Komponente Modell / Beschreibung
Mikrocontroller AZ-Delivery ESP32 DevKit V4
Dot-Matrix-Display 8× GYMAX7219 Module (kompatibel zu MAX7219), 8×8 LEDs je Modul, Typ: GENERIC_HW
Display-Anordnung 4 Module nebeneinander × 2 Reihen = 32×16 LEDs
Display-Kaskadierung Alle 8 Module in einer einzigen SPI-Kette
Stromversorgung Display Externes 5 V-Netzteil erforderlich (gemessen: ~0,5 A / ~2,5 W bei 8 Modulen, Vollast bis ~2 A möglich) ESP32 USB-Port reicht nicht aus
Laser-Aktivsignal Potentialfreier Ausgang des Laser Cutters (Optokoppler empfohlen)
Optional Shelly PM Mini G3 als externer Leistungszähler (separater MQTT-Service)

Pinbelegung

Signal ESP32 GPIO Beschreibung
MAX7219 MOSI GPIO 23 SPI Data (VSPI) → DIN Modul 1
MAX7219 CLK GPIO 18 SPI Clock (VSPI)
MAX7219 CS GPIO 5 SPI Chip Select (alle Module)
Laser-Signal GPIO 4 Potentialfreier Eingang (INPUT_PULLUP, konfigurierbar)

Die Polarität des Laser-Signals (LOW_ACTIVE oder HIGH_ACTIVE) ist über das Webinterface konfigurierbar.

SPI-Ketten-Schaltbild

 ESP32                     OBERE REIHE                            UNTERE REIHE

 GPIO 23 (MOSI) ─── DIN ┌──────┐ DOUT─DIN ┌──────┐ DOUT─DIN ┌──────┐ DOUT─DIN ┌──────┐
                         │ M 1  │          │ M 2  │          │ M 3  │          │ M 4  │
                         │oben  │          │      │          │      │          │oben  │
                         │links │          │      │          │      │          │rechts│
 GPIO 18 (CLK)  ─────────┤ CLK  ├──────────┤ CLK  ├──────────┤ CLK  ├──────────┤ CLK  ├──
 GPIO  5 (CS)   ─────────┤ CS   ├──────────┤ CS   ├──────────┤ CS   ├──────────┤ CS   ├──
                         └──────┘          └──────┘          └──────┘          └──┬───┘
                                                                                   │ DOUT
                         ┌──────┐ DOUT─DIN ┌──────┐ DOUT─DIN ┌──────┐ DOUT─DIN ┌──┴───┐
                         │ M 8  │          │ M 7  │          │ M 6  │          │ M 5  │
                         │unten │          │      │          │      │          │unten │
                         │rechts│          │      │          │      │          │links │
 GPIO 18 (CLK)  ─────────┤ CLK  ├──────────┤ CLK  ├──────────┤ CLK  ├──────────┤ CLK  │
 GPIO  5 (CS)   ─────────┤ CS   ├──────────┤ CS   ├──────────┤ CS   ├──────────┤ CS   │
                         └──────┘          └──────┘          └──────┘          └──────┘

Hinweis: Die untere Reihe läuft im Schaltbild von rechts nach links, weil DOUT von Modul 4 direkt zu DIN von Modul 5 geführt wird. MD_Parola berücksichtigt das automatisch.


Display

Das Display besteht aus 8 GYMAX7219-Modulen in einer 4×2-Anordnung (32×16 LEDs gesamt).
Es ist in zwei Zonen aufgeteilt, die unabhängig voneinander beschrieben werden.

Physisches Layout

  DIN ← ESP32 GPIO 23
  ↓
 ┌─────────┬─────────┬─────────┬─────────┐
 │ Modul 1 │ Modul 2 │ Modul 3 │ Modul 4 │  ← Zone 0 (oben)   0-idx: 03
 │ oben    │         │         │ oben    │    Anzeige: Laserzeit (Minuten)
 │ links   │         │         │ rechts  │
 ├─────────┼─────────┼─────────┼─────────┤
 │ Modul 5 │ Modul 6 │ Modul 7 │ Modul 8 │  ← Zone 1 (unten)  0-idx: 47
 │ unten   │         │         │ unten   │    Anzeige: Countdown / Status
 │ links   │         │         │ rechts  │
 └─────────┴─────────┴─────────┴─────────┘
  SPI-Kette: ESP32 → M1 → M2 → M3 → M4 → M5 → M6 → M7 → M8

Hardware-Typ: GENERIC_HW (verifiziert durch Hardware-Test; physische Ausrichtung erfordert 90° CCW Software-Rotation)

Stromversorgung: Die 8 Module müssen über ein externes 5 V-Netzteil versorgt werden. GND des Netzteils mit ESP32-GND verbinden. Gemessene Leistungsaufnahme im Betrieb: ca. 0,5 A / 2,5 W; bei allen LEDs EIN (Testmuster) bis ca. 2 A möglich.

Zonen-Belegung

Zone 0-Index-Bereich Physisch Anzeige-Inhalt
0 Modul 03 Obere Reihe Akkumulierte aktive Laserzeit in Minuten (z.B. 42.5)
1 Modul 47 Untere Reihe Countdown Gratiszeit in Sekunden, danach ---
  • Die Anzeige aktualisiert sich sekündlich, solange der Laser aktiv ist.
  • Bei inaktivem Laser bleibt die letzte gemessene Zeit dauerhaft sichtbar.
  • Fehlerzustände (WLAN, MQTT) werden in Zone 1 (untere Reihe) angezeigt.
  • Bibliotheken: MD_Parola + MD_MAX72XX

Laser-Signaldetektion

Der ESP32 überwacht einen digitalen GPIO-Eingang mit internem Pull-Up-Widerstand (INPUT_PULLUP).
Der potentialfreie Ausgang des Laser Cutters (z.B. Schließer-Kontakt über Optokoppler) wird an diesen Pin angeschlossen.

  • Polarität konfigurierbar: Im Webinterface einstellbar, ob LOW oder HIGH den aktiven Zustand bedeutet.
  • Debounce: Software-Entprellung, um Fehlmessungen bei Schaltflanken zu vermeiden.
  • Eine Session beginnt, wenn der Laser aktiv wird, und endet, wenn er inaktiv wird.

Zeit-Tracking & Gratiszeit

  • Die Laserzeit wird akkumulativ in Minuten gezählt und über Neustarts hinaus im NVS (Non-Volatile Storage) des ESP32 gespeichert.
  • Gratiszeit: Eine konfigurierbare Zeitspanne (0120 Sekunden) am Anfang jeder Session wird nicht zur akkumulierten Zeit gezählt. Dies erlaubt kurze Testläufe zum Einstellen des Laser Cutters ohne Kosten.
    • Standard: 20 Sekunden
    • Einstellbar über das Webinterface
  • Die untere Display-Zeile zeigt während der Gratiszeit einen Countdown an.

MQTT Client

Der ESP32 verbindet sich mit einem MQTT-Broker (konfigurierbar über Webinterface).

Topics

Richtung Topic Format Beschreibung
Publish lasercutter/session JSON Wird beim Ende einer Session gesendet
Subscribe lasercutter/reset "1" Setzt die akkumulierte Laserzeit auf 0
Publish lasercutter/status JSON Heartbeat alle 60 Sekunden (online/offline)

JSON-Format lasercutter/session

{
  "session_s": 125,
  "total_min": 42.5,
  "gratiszeit_s": 20,
  "ts": "2026-02-22T10:30:00Z"
}

JSON-Format lasercutter/status

{
  "online": true,
  "total_min": 42.5,
  "ip": "192.168.1.100",
  "uptime_s": 3600
}

Verhalten

  • Reconnect im Hintergrund, falls MQTT-Broker nicht erreichbar.
  • Bei aktivem Laser läuft die Zeitmessung unabhängig vom MQTT-Status weiter.
  • QoS 1 für Session- und Reset-Topics.

Webinterface

Das Webinterface ist über die IP-Adresse des ESP32 im Browser erreichbar.

Seite URL Funktion
Status / Aktuelle Laserzeit, letzter Session-Wert, Systemstatus
Konfiguration /config MQTT-Broker (IP, Port, User, Passwort), Gratiszeit, Polarität
Reset /reset Setzt akkumulierte Laserzeit zurück
OTA Update /update Firmware-Update über Browser

Konfiguration & Persistenz

Alle Einstellungen werden im NVS (Non-Volatile Storage) des ESP32 gespeichert und sind über das Webinterface änderbar:

Einstellung Standard Beschreibung
MQTT Broker IP 192.168.1.1 IP-Adresse des MQTT-Brokers
MQTT Port 1883 Port des MQTT-Brokers
MQTT User (leer) MQTT Benutzername (optional)
MQTT Passwort (leer) MQTT Passwort (optional)
Gratiszeit 20 Sekunden, 0120
Signal-Polarität LOW_ACTIVE LOW_ACTIVE oder HIGH_ACTIVE
Akkumulierte Zeit 0.0 Gespeicherte Laserzeit in Minuten (NVS)

WiFi-Setup (WiFiManager)

Beim ersten Start (oder wenn keine gespeicherten WLAN-Daten vorhanden) öffnet das Gerät einen Access Point mit Captive Portal:

  • SSID: LaserCutter-Setup
  • Im Browser öffnet sich automatisch die Konfigurationsseite.
  • WLAN-Credentials werden nach erfolgreicher Verbindung im NVS gespeichert.

OTA Firmware-Update

Firmware-Updates können kabellos über die Weboberfläche unter /update eingespielt werden (ElegantOTA).


Fehlerverhalten

Zustand Display-Anzeige (untere Zeile, Modul 1) Verhalten
WLAN getrennt WiFi ERR Zeiterfassung läuft weiter, Reconnect
MQTT nicht erreichbar MQTT ERR Zeiterfassung läuft weiter, Reconnect
WLAN + MQTT OK Normaler Betrieb (Countdown/---)

Bibliotheken

Bibliothek Zweck
MD_Parola Dot-Matrix-Display Textausgabe
MD_MAX72XX Treiber für MAX7219/GYMAX7219
PubSubClient MQTT Client
WiFiManager WiFi Captive Portal
ESPAsyncWebServer Asynchroner Webserver
AsyncTCP TCP-Basis für ESPAsyncWebServer
ArduinoJson JSON Serialisierung/Deserialisierung
Preferences NVS-Zugriff (built-in ESP32 Arduino)
ElegantOTA OTA-Update über Webinterface

Build & Flash

# PlatformIO CLI
pio run --target upload

# Serieller Monitor
pio device monitor

Ziel-Board: az-delivery-devkit-v4 (ESP32), Upload-Port: COM3


Projektstruktur

MQTT-Display-LaserCutter/
├── src/
│   └── main.cpp              # Hauptprogramm
├── include/
│   ├── config.h              # Pin-Definitionen, Konstanten
│   ├── display_manager.h     # Display-Logik (MD_Parola)
│   ├── laser_tracker.h       # Signal-Detektion & Zeiterfassung
│   ├── mqtt_client.h         # MQTT-Wrapper (PubSubClient)
│   ├── web_server.h          # Webinterface (ESPAsyncWebServer)
│   └── settings.h            # NVS-Persistenz (Preferences)
├── parser/
│   └── shelly_parser.py      # Separater Python-Parser für Shelly PM G3
├── platformio.ini
└── README.md

Beitragen / Commits

Dieses Projekt verwendet Conventional Commits für alle Git-Commit-Nachrichten.

Format

<type>(<scope>): <kurze Beschreibung>

[optionaler Body]

[optionaler Footer]

Wichtigste Typen

Typ Verwendung
feat Neues Feature
fix Bugfix
docs Nur Dokumentation
refactor Code-Umstrukturierung ohne Feature/Fix
test Test-Sketches / Test-Code
chore Build-System, Abhängigkeiten, Konfiguration

Beispiele

feat(display): add GENERIC_HW rotation compensation
fix(nvs): prevent crash on empty broker string
docs(readme): add power supply requirements
chore(platformio): reduce SPI clock to 1 MHz for stability

Breaking Changes werden mit ! nach dem Typ markiert oder im Footer mit BREAKING CHANGE: beschrieben.