541 lines
24 KiB
Markdown
541 lines
24 KiB
Markdown
# 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](#hardware)
|
||
2. [Pinbelegung](#pinbelegung)
|
||
3. [Display](#display)
|
||
4. [Laser-Signaldetektion](#laser-signaldetektion)
|
||
5. [Zeit-Tracking & Gratiszeit](#zeit-tracking--gratiszeit)
|
||
6. [MQTT Client](#mqtt-client)
|
||
7. [Webinterface](#webinterface)
|
||
8. [Konfiguration & Persistenz](#konfiguration--persistenz)
|
||
9. [WiFi-Setup (WiFiManager)](#wifi-setup-wifimanager)
|
||
10. [OTA Firmware-Update](#ota-firmware-update)
|
||
11. [Fehlerverhalten](#fehlerverhalten)
|
||
12. [Bibliotheken](#bibliotheken)
|
||
13. [Build & Flash](#build--flash)
|
||
14. [Tests](#tests)
|
||
15. [Beitragen / Commits](#beitragen--commits)
|
||
|
||
---
|
||
## Skizze und Screenshots
|
||
|
||

|
||
|
||
Das Bild zeigt die physische Anordnung der 8 GYMAX7219-Module im 4×2-Format mit LED-Positionen und Beschriftung der Anzeigebereiche.
|
||
|
||

|
||
|
||

|
||
|
||

|
||
|
||
|
||
## 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: 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.
|
||
|
||
### Modul-Belegung
|
||
|
||
| Modul(e) | 0-Index | Physisch | Anzeige-Inhalt |
|
||
|----------|---------|-------------------|---------------------------------------------------------------|
|
||
| 0 | 0 | Oben links | **WiFi-Fehler** (`E` = kein WLAN, leer = OK) |
|
||
| 1–3 | 1–3 | Oben Mitte–rechts | **Session-Minuten** ganzzahlig (0 bei Neustart, RAM-only) |
|
||
| 4 | 4 | Unten links | **MQTT-Fehler** (`E` = kein Broker, leer = OK) |
|
||
| 5–7 | 5–7 | Unten Mitte–rechts| **Countdown** (Gratiszeit in Sek.) oder `--` (Idle/Netto) |
|
||
|
||
- Session-Minuten (Module 1–3) inkrementierten erst nach vollen **60 Netto-Sekunden** (harte Ganzzahl).
|
||
- Die Netto-Zeit beginnt erst nach Ablauf der Gratiszeit (Laser muss länger als `gratisSeconds` aktiv bleiben).
|
||
- Die Anzeige aktualisiert sich im `loop()` ohne Blocking-Delays.
|
||
- Bibliotheken: `MD_MAX72XX` (direkte Puffer-Steuerung, keine MD_Parola)
|
||
|
||
---
|
||
|
||
## 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
|
||
|
||
### Zwei getrennte Zeitkreise
|
||
|
||
| Kreis | Speicher | Reset | Verwendung |
|
||
|---|---|---|---|
|
||
| **Session-Minuten** | RAM | bei Neustart / `resetSession()` | Display Module 1–3 |
|
||
| **Gesamtzeit** | NVS (`total_min`) | nur per `resetTotal()` | MQTT, Web-UI, Wartungsstatistik |
|
||
|
||
### Burst-Zustandsmaschine
|
||
|
||
Jedes Laser-AN-Ereignis durchläuft drei Zustände:
|
||
|
||
```
|
||
INACTIVE ──(Laser an)──► GRATIS ──(Gratiszeit abgelaufen)──► NET_COUNTING
|
||
▲ │ │
|
||
└───────────────────────┴──────────(Laser aus)─────────────────┘
|
||
```
|
||
|
||
| Zustand | Display unten | Netto-Zeit | NVS |
|
||
|---|---|---|---|
|
||
| `INACTIVE` | `--` | – | – |
|
||
| `GRATIS` | Countdown (z.B. `19`, `18`, ...) | läuft nicht | – |
|
||
| `NET_COUNTING` | `--` | läuft | – |
|
||
| → Laser aus (aus `NET_COUNTING`) | `--` | wird addiert | gespeichert |
|
||
| → Laser aus (aus `GRATIS`) | `--` | 0 addiert | Burst-Dauer gespeichert |
|
||
|
||
### Gratiszeit
|
||
|
||
- Konfigurierbar: 0–120 Sekunden (Standard: **20 s**)
|
||
- Startet **neu bei jedem** Laser-AN-Ereignis
|
||
- Geht der Laser während der Gratiszeit wieder aus: keine Session-Zeit, aber NVS zählt die Einschaltdauer
|
||
- Einstellbar über das Webinterface
|
||
|
||
### NVS-Gesamtzeit
|
||
|
||
Zählt **jede Sekunde Laser-AN**, inklusive Gratiszeit. Eignet sich für Wartungsintervalle (tatsächliche Einschaltdauer des Lasers).
|
||
|
||
### Session-Minuten (Display)
|
||
|
||
Zählt nur die **Netto-Zeit** (nach Ablauf der Gratiszeit). Inkrementiert hart bei 60 / 120 / 180 ... Netto-Sekunden. Wird bei Neustart und `resetSession()` auf 0 zurückgesetzt.
|
||
|
||
---
|
||
|
||
## 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 eines Laser-Bursts** gesendet |
|
||
| Publish | `lasercutter/status` | JSON (retained) | Heartbeat alle 60 Sekunden + LWT (online/offline) |
|
||
| Subscribe | `lasercutter/reset` | `{"reset":true}` oder `"1"` | Setzt die akkumulierte Laserzeit auf 0 |
|
||
|
||
### JSON-Format `lasercutter/session`
|
||
```json
|
||
{
|
||
"session_s": 125,
|
||
"total_min": "42.50",
|
||
"gratiszeit_s": 20,
|
||
"ip": "192.168.1.100"
|
||
}
|
||
```
|
||
|
||
### JSON-Format `lasercutter/status`
|
||
```json
|
||
{
|
||
"online": true,
|
||
"total_min": "42.50",
|
||
"ip": "192.168.1.100",
|
||
"uptime_s": 3600
|
||
}
|
||
```
|
||
|
||
### LWT (Last Will and Testament)
|
||
Bei Verbindungsabbruch sendet der Broker automatisch auf `lasercutter/status`:
|
||
```json
|
||
{"online": false}
|
||
```
|
||
|
||
### Verhalten
|
||
- Non-Blocking Reconnect alle 10 s, falls MQTT-Broker nicht erreichbar.
|
||
- Bei aktivem Laser läuft die Zeitmessung unabhängig vom MQTT-Status weiter.
|
||
- Client-ID: `lasercutter-display-XXXXXX` (mit MAC-Suffix, eindeutig auf Public Broker).
|
||
- TLS (Port 8883): wird automatisch aktiviert wenn Port 8883 konfiguriert ist (`WiFiClientSecure`, `setInsecure`).
|
||
|
||
---
|
||
|
||
## 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 | `broker.hivemq.com` | Hostname oder IP des MQTT-Brokers |
|
||
| MQTT Port | `1883` | Port des MQTT-Brokers (8883 = TLS auto) |
|
||
| 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 | Modul 0 (oben links) | Modul 4 (unten links) | Verhalten |
|
||
|-----------------------|---------------------|-----------------------|---------------------------------------|
|
||
| WLAN getrennt | `E` (blinkt) | – | Zeiterfassung läuft weiter, Reconnect |
|
||
| MQTT nicht erreichbar | – | `E` (blinkt) | Zeiterfassung läuft weiter, Reconnect |
|
||
| WLAN + MQTT OK | leer | leer | Normaler Betrieb |
|
||
|
||
---
|
||
|
||
## Bibliotheken
|
||
|
||
| Bibliothek | Zweck |
|
||
|-----------------------|---------------------------------------------------------------------|
|
||
| `MD_MAX72XX` | Treiber für MAX7219/GYMAX7219, direkte Puffer-Steuerung |
|
||
| `MD_Parola` | (Dependency von MD_MAX72XX, nicht direkt genutzt) |
|
||
| `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
|
||
|
||
```bash
|
||
# Haupt-Firmware bauen und flashen
|
||
pio run -e az-delivery-devkit-v4 --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
|
||
│ ├── display_manager.cpp # Display-Implementierung (MD_MAX72XX)
|
||
│ ├── laser_tracker.cpp # Signal-Detektion, Burst-Logik, Zeiterfassung
|
||
│ ├── settings.cpp # NVS-Persistenz (Preferences)
|
||
│ ├── wifi_connector.cpp # WiFiManager-Wrapper
|
||
│ ├── mqtt_client.cpp # MQTT-Wrapper (PubSubClient, TLS, Phase 6)
|
||
│ └── web_server.cpp # Webinterface (ESPAsyncWebServer, Phase 7)
|
||
├── include/
|
||
│ ├── config.h # Pin-Definitionen, Konstanten
|
||
│ ├── display_manager.h # Display-API (showLaserTime, showCountdown, ...)
|
||
│ ├── laser_tracker.h # BurstState-Maschine, getSessionMinutes(), ...
|
||
│ ├── settings.h # Settings-Struct, SettingsManager
|
||
│ ├── wifi_connector.h # WiFi-Verbindungsmanagement
|
||
│ ├── mqtt_client.h # (Phase 6) MQTT-Wrapper (PubSubClient)
|
||
│ └── web_server.h # (Phase 7) Webinterface (ESPAsyncWebServer)
|
||
├── test_sketches/
|
||
│ ├── test_display.cpp # 1.4 - GYMAX7219 Moduldignose
|
||
│ ├── test_button.cpp # 1.5 - Potentialfreier Schalter
|
||
│ ├── test_nvs.cpp # 2.2 - NVS Persistenz
|
||
│ ├── test_wifi.cpp # 3.3 - WiFiManager
|
||
│ ├── test_display_manager.cpp # 4.3 - DisplayManager
|
||
│ ├── test_laser_tracker.cpp # 5.6 - LaserTracker
|
||
│ ├── test_mqtt_client.cpp # 6.5 - MqttClient (TLS, Session, Heartbeat)
|
||
│ ├── test_web_server.cpp # 7.7 - WebServer (Routen, Config, OTA)
|
||
│ └── mqtt_test_secrets.h # (gitignoriert) persönliche Broker-Credentials
|
||
├── platformio.ini
|
||
└── README.md
|
||
```
|
||
---
|
||
|
||
## Tests
|
||
|
||
Alle Tests sind Hardware-Tests (kein Unit-Test-Framework). Sie werden als separate PlatformIO-Environments geflasht und über den Serial Monitor beobachtet.
|
||
|
||
### Übersicht
|
||
|
||
| Nr. | Environment | Datei | Testet |
|
||
|-----|-----------------------|------------------------------|-----------------------------------------------------|
|
||
| 1.4 | `test-display` | `test_display.cpp` | GYMAX7219 Verkabelung, Modul-Nummerierung, Rotation |
|
||
| 1.5 | `test-button` | `test_button.cpp` | Potentialfreier Schalter / Debounce an GPIO 4 |
|
||
| 2.2 | `test-nvs` | `test_nvs.cpp` | NVS Lesen/Schreiben/Reset (SettingsManager) |
|
||
| 3.3 | `test-wifi` | `test_wifi.cpp` | WiFiManager Captive Portal, WLAN-Verbindung |
|
||
| 4.3 | `test-display-mgr` | `test_display_manager.cpp` | DisplayManager API (alle show*-Methoden) |
|
||
| 5.6 | `test-laser-tracker` | `test_laser_tracker.cpp` | LaserTracker Burst-Logik, Gratiszeit, Session/NVS |
|
||
| 6.5 | `test-mqtt` | `test_mqtt_client.cpp` | MqttClient TLS, Heartbeat, Session-Publish, JSON-Reset, LWT |
|
||
| 7.7 | `test-web` | `test_web_server.cpp` | WebServer Routen, Config-Formular, Reset, ElegantOTA OTA |
|
||
|
||
### Test 1.4 – Display Verdrahtungstest
|
||
|
||
```bash
|
||
pio run -e test-display --target upload
|
||
pio device monitor -e test-display
|
||
```
|
||
|
||
Erwartetes Verhalten: Alle 8 Module zeigen nacheinander ihre Nummer, danach Laufschrift und Fülltest.
|
||
|
||
### Test 1.5 – Button / Laser-Eingang
|
||
|
||
```bash
|
||
pio run -e test-button --target upload
|
||
pio device monitor -e test-button
|
||
```
|
||
|
||
Erwartetes Verhalten: Serial-Ausgabe zeigt `HIGH`/`LOW` beim Betätigen des Schalters an GPIO 4.
|
||
|
||
### Test 2.2 – NVS Persistenz
|
||
|
||
```bash
|
||
pio run -e test-nvs --target upload
|
||
pio device monitor -e test-nvs
|
||
```
|
||
|
||
Erwartetes Verhalten: Schreibt Testwerte in NVS, liest sie zurück, prüft Übereinstimmung. Nach Neustart müssen die Werte erhalten bleiben. Alle Tests als `PASS` im Serial Monitor.
|
||
|
||
### Test 3.3 – WiFiManager
|
||
|
||
```bash
|
||
pio run -e test-wifi --target upload
|
||
pio device monitor -e test-wifi
|
||
```
|
||
|
||
Erwartetes Verhalten: Beim ersten Flash öffnet der ESP32 den AP `LaserCutter-Setup`. Nach Eingabe der WLAN-Credentials verbindet er sich und gibt die IP-Adresse aus. BOOT-Taste (GPIO 0) beim Start 3 s halten löscht gespeicherte Credentials.
|
||
|
||
### Test 4.3 – DisplayManager
|
||
|
||
```bash
|
||
pio run -e test-display-mgr --target upload
|
||
pio device monitor -e test-display-mgr
|
||
```
|
||
|
||
Erwartetes Verhalten: Durchläuft automatisch alle `show*`-Methoden:
|
||
- `showWifiError(true/false)` → Modul 0
|
||
- `showLaserTime(n)` → Module 1–3 (ganze Minuten: 0, 1, 42, 999)
|
||
- `showMqttError(true/false)` → Modul 4
|
||
- `showCountdown(n)` → Module 5–7
|
||
- `showIdle()` → Module 5–7 (`--`)
|
||
|
||
### Test 5.6 – LaserTracker
|
||
|
||
```bash
|
||
pio run -e test-laser-tracker --target upload
|
||
pio device monitor -e test-laser-tracker
|
||
```
|
||
|
||
**GPIO 4 Schalter** betätigen = Laser-AN simulieren.
|
||
|
||
Erwartetes Verhalten:
|
||
|
||
| Aktion | Module 1–3 | Module 5–7 | Serial |
|
||
|---|---|---|---|
|
||
| Idle | `0` | `--` | – |
|
||
| Laser an (0–20 s) | `0` | Countdown `20`→`1` | `BurstStart -> GRATIS` |
|
||
| Laser an (>20 s) | `0` | `--` | `GRATIS abgelaufen -> NET_COUNTING` |
|
||
| Laser aus (nach 80 s netto) | `1` | `--` | `BurstEnd: gesamt=... netto=...` |
|
||
| Nach 60 weiteren Netto-Sek. | `2` | `--` | – |
|
||
|
||
**BOOT-Taste (GPIO 0) 3 s halten** → `settings.reset()` + `resetTotal()` → alle NVS-Werte auf Default, Session = 0.
|
||
|
||
### Test 6.5 – MqttClient (Phase 6)
|
||
|
||
> ⚠️ Voraussetzung: `test_sketches/mqtt_test_secrets.h` anlegen (Vorlage: `mqtt_test_secrets.h.example`)
|
||
|
||
```bash
|
||
pio run -e test-mqtt --target upload
|
||
pio device monitor -e test-mqtt
|
||
```
|
||
|
||
**Erwartetes Verhalten:**
|
||
|
||
| Aktion | Serial / MQTT Explorer |
|
||
|---|---|
|
||
| Start | Verbindung zu Broker, `lasercutter/status` retained `{"online":true,...}` |
|
||
| Alle 30 s | Heartbeat auf `lasercutter/status` mit `uptime_s` |
|
||
| Laser AN/AUS (>20 s) | Session-Publish auf `lasercutter/session` |
|
||
| `{"reset":true}` senden an `lasercutter/reset` | `resetTotal()` → Session = 0 |
|
||
| ESP32 stromlos | LWT `{"online":false}` erscheint nach Keep-Alive-Timeout |
|
||
| Modul 4 | `E` blinkt bei MQTT-Verbindungsverlust |
|
||
|
||
**BOOT-Taste (GPIO 0) 3 s halten** → `resetTotal()` → Gesamtzeit auf 0.
|
||
|
||
**Status:** ✅ Verbindung, Heartbeat, Session-Publish, JSON-Reset, LWT getestet
|
||
⚠️ **Ungetestet:** MQTT-Error Modul 5 bei Verbindungsverlust, Reconnect nach WiFi-Ausfall
|
||
|
||
### Test 7.7 – WebServer (Phase 7)
|
||
|
||
```bash
|
||
pio run -e test-web --target upload
|
||
pio device monitor -e test-web
|
||
```
|
||
|
||
IP-Adresse aus Serial Monitor ablesen, dann im Browser:
|
||
|
||
| URL | Erwartetes Verhalten |
|
||
|---|---|
|
||
| `http://<IP>/` | Statusseite: Session, Gesamtzeit (NVS), WLAN-IP, MQTT-Status, Broker |
|
||
| `http://<IP>/config` | Formular: Broker, Port, User, PW, Gratiszeit, Polarität |
|
||
| POST `/config` | Werte in NVS speichern, nach Neustart prüfen |
|
||
| Button „Session zurücksetzen“ | `resetSession()` → Session = 0 min, Gesamtzeit (NVS) bleibt erhalten |
|
||
| `http://<IP>/update` | ElegantOTA-Seite erreichbar |
|
||
|
||
Statusseite aktualisiert sich automatisch alle 10 s.
|
||
|
||
**Status:** ⏳ Hardware-Test ausstehend
|
||
|
||
---
|
||
|
||
## Implementierungsstand
|
||
|
||
| Phase | Beschreibung | Status |
|
||
|-------|-------------|--------|
|
||
| 1 | Hardware-Grundtest (Display, Button) | ✅ abgeschlossen |
|
||
| 2 | NVS-Persistenz (Settings) | ✅ abgeschlossen |
|
||
| 3 | WiFiManager | ✅ abgeschlossen |
|
||
| 4 | DisplayManager | ✅ abgeschlossen |
|
||
| 5 | LaserTracker (Burst-Logik, Zeiterfassung) | ✅ abgeschlossen |
|
||
| 6 | MqttClient (PubSubClient, TLS, Heartbeat, Session) | ✅ implementiert / ⚠️ 2 Punkte ungetestet |
|
||
| 7 | WebServer (ESPAsyncWebServer, Config-UI, OTA) | ✅ implementiert / ⏳ Hardware-Test ausstehend |
|
||
| 8 | Integrationstest (Display + MQTT + Web) | ⏳ ausstehend |
|
||
| 9 | Gehäuse / Hardware-Finish | ⏳ ausstehend |
|
||
| 10 | Produktiv-Deployment, Dokumentation final | ⏳ ausstehend |
|
||
|
||
---
|
||
|
||
## Beitragen / Commits
|
||
|
||
Dieses Projekt verwendet **[Conventional Commits](https://www.conventionalcommits.org/)** 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. |