- 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 |
||
|---|---|---|
| .vscode | ||
| include | ||
| lib | ||
| parser | ||
| src | ||
| test | ||
| test_sketches | ||
| .gitignore | ||
| Implementation-Plan.md | ||
| platformio.ini | ||
| README.md | ||
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
- Hardware
- Pinbelegung
- Display
- Laser-Signaldetektion
- Zeit-Tracking & Gratiszeit
- MQTT Client
- Webinterface
- Konfiguration & Persistenz
- WiFi-Setup (WiFiManager)
- OTA Firmware-Update
- Fehlerverhalten
- Bibliotheken
- Build & Flash
- 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_ACTIVEoderHIGH_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: 0–3
│ oben │ │ │ oben │ Anzeige: Laserzeit (Minuten)
│ links │ │ │ rechts │
├─────────┼─────────┼─────────┼─────────┤
│ Modul 5 │ Modul 6 │ Modul 7 │ Modul 8 │ ← Zone 1 (unten) 0-idx: 4–7
│ 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 0–3 | Obere Reihe | Akkumulierte aktive Laserzeit in Minuten (z.B. 42.5) |
| 1 | Modul 4–7 | 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
LOWoderHIGHden 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 (0–120 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, 0–120 |
| 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.