MQTT-Display-LaserCutter/test_sketches/README.md

449 lines
17 KiB
Markdown

# Test Sketches - Hardware-Verifikationstests
Eigenstaendige Test-Sketches zur Verifikation der Hardware und einzelner Subkomponenten.
Jeder Sketch laeuft als separates PlatformIO-Environment und beruehrt `src/main.cpp` nicht.
### Ü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 Session-Logik, Gratiszeit, Summe 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 |
---
## Physisches Display-Layout (GYMAX7219, 4x2)
```
DIN <- ESP32 GPIO 23
|
+----------+----------+----------+----------+
| Modul 1 | Modul 2 | Modul 3 | Modul 4 | <- Obere Reihe (0-idx: 0-3)
| links | | | rechts |
+----------+----------+----------+----------+
| Modul 5 | Modul 6 | Modul 7 | Modul 8 | <- Untere Reihe (0-idx: 4-7)
| links | | | rechts |
+----------+----------+----------+----------+
DOUT Modul 4 -> DIN Modul 5 (Reihen verbinden)
```
SPI-Datenfluss: ESP32 -> Modul 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
**Hardware-Typ:** `GENERIC_HW` (verifiziert; 90 Grad CCW Software-Rotation aktiv per `rotateCCW()`)
### Modul-Belegung im Betrieb
| Modul(e) | 0-Index | Funktion |
|-----------|---------|-------------------------------------------------------|
| Modul 1 | 0 | WiFi-Fehler-Indikator (`E` = kein WLAN, leer = OK) |
| Modul 2-4 | 1-3 | Summe Session-Minuten ganzzahlig (0 bei Neustart, RAM-only) |
| Modul 5 | 4 | MQTT-Fehler-Indikator (`E` = kein Broker, leer = OK) |
| Modul 6-8 | 5-7 | Countdown (Gratiszeit) oder `--` (Idle/Netto) |
---
## Test 1.4 - Dot-Matrix-Display (`test_display.cpp`)
### Zweck
Verdrahtung und Ausrichtung aller 8 GYMAX7219-Module pruefen.
### Flash & Monitor
```bash
pio run -e test-display --target upload
pio device monitor -e test-display
```
### Verdrahtung
| ESP32 GPIO | Modul-Pin | Beschreibung |
|---------------|-----------|-----------------------------------------------------------|
| GPIO 23 | DIN | SPI Data (VSPI MOSI) |
| GPIO 18 | CLK | SPI Clock |
| GPIO 5 | CS / LOAD | SPI Chip Select |
| GND | GND | Masse (gemeinsam mit ESP32 GND) |
| **5V extern** | VCC | **Externes Netzteil >= 1 A** (USB-Port reicht nicht aus) |
### Erwartetes Verhalten
1. Alle LEDs EIN (2 s) - alle 8 Module leuchten
2. Jedes Modul zeigt seine Nummer einzeln
3. Realistische Anzeige: Minuten oben, Countdown unten
Text erscheint lesbar (nicht gespiegelt oder kopfstehend).
### Ergebnis
- [x] GYMAX7219 mit `GENERIC_HW` + 90 Grad CCW Software-Rotation
- [x] Modul 1 oben-links, Modul 8 unten-rechts
- [x] Externes 5 V-Netzteil notwendig
---
## Test 1.5 - Potentialfreier Schalter (`test_button.cpp`)
### Zweck
GPIO-Eingang (INPUT_PULLUP) testen, Pegel und Entprellzeit verifizieren.
### Flash & Monitor
```bash
pio run -e test-button --target upload
pio device monitor -e test-button
```
### Verdrahtung
```
ESP32 GPIO 4 ----| Button |----- GND (kein externer Widerstand noetig)
```
### Erwartetes Verhalten
| Zustand | GPIO-Pegel | Serial-Ausgabe |
|------------------|------------|----------------------|
| Schalter offen | HIGH | `HIGH (inaktiv)` |
| Schalter geschl. | LOW | `LOW -> LASER AKTIV` |
### Ergebnis
- [x] `LOW_ACTIVE`-Polaritaet bestaetigt
- [x] Debounce 50 ms funktioniert
---
## Test 2.2 - NVS Persistenz (`test_nvs.cpp`)
### Zweck
Schreiben, Lesen und Reset aller NVS-Werte ueber den `SettingsManager` pruefen.
### Flash & Monitor
```bash
pio run -e test-nvs --target upload
pio device monitor -e test-nvs
```
### Testablauf
1. Testwerte in NVS schreiben (MQTT-Config, gratisSeconds, totalMinutes, Polaritaet)
2. NVS-Werte zuruecklesen und pruefen
3. ESP32 neu starten -> Werte muessen erhalten bleiben
4. `settings.reset()` aufrufen -> alle Werte auf Default zurueck
### Erwartetes Verhalten
Alle Pruefungen als `PASS` im Serial Monitor. Nach Neustart bleiben geschriebene Werte erhalten.
### Ergebnis
- [x] NVS Roundtrip fuer alle Felder bestanden
- [x] `reset()` setzt auf Defaults zurueck
- [x] Persistenz ueber Neustart bestaetigt
---
## Test 3.3 - WiFiManager (`test_wifi.cpp`)
### Zweck
WiFiManager Captive Portal und WLAN-Verbindungsaufbau testen.
### Flash & Monitor
```bash
pio run -e test-wifi --target upload
pio device monitor -e test-wifi
```
### Testablauf
1. **Erstes Flash:** ESP32 oeffnet AP `LaserCutter-Setup`
2. Mit Handy/PC mit AP verbinden - Captive Portal oeffnet sich automatisch
3. WLAN-Credentials eingeben und speichern
4. ESP32 verbindet sich mit dem WLAN und gibt IP-Adresse aus
5. **BOOT-Taste (GPIO 0) beim Start 3 s halten** -> gespeicherte Credentials loeschen, AP neu oeffnen
### Erwartetes Verhalten
Nach erfolgreicher Verbindung im Serial Monitor:
```
[WiFi] Verbunden: 192.168.x.x
```
### Ergebnis
- [x] Captive Portal startet korrekt
- [x] Credentials werden in NVS gespeichert
- [x] Reconnect nach Neustart ohne Portal
---
## Test 4.3 - DisplayManager (`test_display_manager.cpp`)
### Zweck
Alle `show*`-Methoden des `DisplayManager` auf korrektes Modul-Mapping und Darstellung pruefen.
### Flash & Monitor
```bash
pio run -e test-display-mgr --target upload
pio device monitor -e test-display-mgr
```
### Testablauf (automatisch, kein Eingriff noetig)
Der Sketch durchlaeuft nacheinander:
| Schritt | Methode | Modul(e) | Erwartete Anzeige |
|---------|---------------------------|----------|----------------------------|
| 1 | `showWifiError(true)` | 0 | `E` |
| 2 | `showWifiError(false)` | 0 | leer |
| 3 | `showLaserTime(0)` | 1-3 | ` 0` |
| 4 | `showLaserTime(42)` | 1-3 | ` 42` |
| 5 | `showLaserTime(999)` | 1-3 | `999` |
| 6 | `showMqttError(true)` | 4 | `E` |
| 7 | `showMqttError(false)` | 4 | leer |
| 8 | `showCountdown(20)` | 5-7 | ` 20` |
| 9 | `showCountdown(1)` | 5-7 | ` 1` |
| 10 | `showIdle()` | 5-7 | ` --` |
### Ergebnis
- [x] Alle Module reagieren auf die korrekten Methoden
- [x] showLaserTime() zeigt ganze Zahlen rechtbuendig
- [x] Fehler-Indikatoren auf Modul 0 und 4 unabhaengig voneinander
---
## Test 5.6 - LaserTracker (`test_laser_tracker.cpp`)
### Zweck
Session-Zustandsmaschine, Gratiszeit-Countdown, Summe Session-Minuten und NVS-Gesamtzeit pruefen.
### Flash & Monitor
```bash
pio run -e test-laser-tracker --target upload
pio device monitor -e test-laser-tracker
```
### Verdrahtung
GPIO 4: Push-Button gegen GND (simuliert Laser-AN/AUS, LOW_ACTIVE)
### Testablauf
**A) Gratis-Session (Laser < 20 s):**
1. Schalter schliessen -> Countdown startet auf Modul 6-8
2. Schalter vor Ablauf der 20 s oeffnen
3. Erwartung: Summe Session-Minuten unveraendert (0), NVS erhoehte sich um Session-Dauer
**B) Netto-Session (Laser > 20 s):**
1. Schalter schliessen -> Countdown startet
2. Nach 20 s -> Countdown erlischt, Module 6-8 zeigen `--`
3. Schalter nach z.B. 80 Netto-Sekunden oeffnen
4. Erwartung: keine Minutenaenderung (80 s < 60 s ist falsch; 80 s >= 60 s -> +1 Minute auf Modul 2-4)
**C) Neustart-Test:**
1. ESP32 neu starten
2. Erwartung: Summe Session-Minuten = 0 auf Modul 2-4
3. NVS-Gesamtzeit aus vorherigen Sessions bleibt erhalten (im Serial Monitor sichtbar)
**D) Komplett-Reset:**
1. BOOT-Taste (GPIO 0) 3 Sekunden halten
2. Erwartung: `settings.reset()` + `resetTotal()` -> gratisSeconds = 20, totalMinutes = 0
### Erwartetes Display-Verhalten
| Zustand | Module 1-3 (Session) | Module 5-7 (Status) |
|----------------------------|----------------------|-----------------------|
| Idle | ` 0` | ` --` |
| Laser an (0-20 s) | ` 0` | `20` -> `1` Countdown |
| Laser an (> 20 s) | ` 0` | ` --` |
| Laser aus nach 80 Netto-s | ` 1` | ` --` |
| Neustart | ` 0` | ` --` |
### Ergebnis
- [x] GRATIS -> NET_COUNTING Uebergang nach 20 s
- [x] Session-Minuten incrementieren hart bei 60 Netto-Sekunden
- [x] Gratis-Sessions addieren keine Session-Zeit
- [x] Gratis-Sessions senden kein MQTT-Publish
- [x] NVS zaehlt gesamte Laser-AN-Zeit (inkl. Gratiszeit)
- [x] resetTotal() loescht NVS + Session
---
## Test 6.5 - MqttClient (`test_mqtt_client.cpp`)
### Zweck
MQTT-Verbindung, Session-Publish, Heartbeat und Reset-Subscribe ueber `broker.hivemq.com` pruefen.
### Flash & Monitor
```bash
pio run -e test-mqtt --target upload
pio device monitor -e test-mqtt
```
### Vorbereitung: MQTT Explorer
1. MQTT Explorer herunterladen: https://mqtt-explorer.com (kostenlos, Windows/Mac/Linux)
2. Neue Verbindung anlegen:
- Host: `broker.hivemq.com`
- Port: `1883`
- Kein Username / Passwort
3. Verbinden -> `lasercutter/#` wird automatisch angezeigt
### Testablauf
**A) Verbindung & Heartbeat:**
1. ESP32 flashen und starten
2. Serial Monitor: `[MQTT] Verbunden!` und sofortiger Heartbeat erwartet
3. Im MQTT Explorer: `lasercutter/status` erscheint mit `{"online":true,...}` (retained)
4. Nach 60 s: erneuter Heartbeat sichtbar
**B) Session-Publish nach Session-Ende:**
1. GPIO 4 Taste druecken (Laser AN) -> Countdown auf Modul 6-8
2. Taste loslassen (Laser AUS) **nach** Ablauf der Gratiszeit
3. Serial: `SessionEnd -> publishSession`
4. MQTT Explorer: `lasercutter/session` erscheint mit JSON:
```json
{"session_minutes": 1, "session_seconds": 5, "freetime_s": 20, "ip": "192.168.x.x"}
```
**C) Gratis-Session (< 20 s):**
1. Taste < 20 s druecken und loslassen
2. **Kein Publish** auf `lasercutter/session` (Netto-Zeit = 0s)
3. `machine_running_time_min` im naechsten Heartbeat erhoehte sich trotzdem (Gratiszeit zaehlt in NVS)
**D) Reset-Kommando via MQTT:**
1. Im MQTT Explorer auf Topic `lasercutter/reset` publishen
- JSON-Payload (empfohlen): `{"reset":true}`
- Alternativ Plain: `1`
2. Serial: `[MQTT] RESET-Kommando empfangen -> laserTracker.resetTotal()`
3. Naechster Heartbeat zeigt `"total_min": "0.00"`
**E) LWT (Last Will und Testament):**
1. USB-Kabel ziehen (oder Strom aus)
2. Nach ca. 60 s (Broker Keep-Alive-Timeout) erscheint im MQTT Explorer:
- `lasercutter/status` -> `{"online":false}` (retained, vom Broker versendet)
**F) Reconnect-Test:**
1. WiFi-Router kurz ausschalten oder ESP32 in WLAN-toten Bereich bringen
2. Serial: alle 10 s `[MQTT] Verbindung fehlgeschlagen, rc=-2`
3. Modul 5 zeigt `E` (MQTT-Fehler-Indikator)
4. WiFi wieder einschalten -> automatischer Reconnect, `E` erlischt
**G) BOOT-Taste lokaler Reset:**
1. BOOT-Taste (GPIO 0) 3 s halten
2. Serial: `BOOT 3s: Gesamtzeit loeschen`
3. `total_min` springt auf 0
### Erwartetes Serial-Verhalten (Auszug)
```
[I][TEST-MQTT] === Phase 6 MQTT Test gestartet ===
[I][TEST-MQTT] Broker Default: broker.hivemq.com:1883
[MQTT] Broker: broker.hivemq.com:1883
[MQTT] Client-ID: lasercutter-display
[MQTT] Verbinde als 'lasercutter-display'...
[MQTT] Verbunden!
[MQTT] Abonniert: lasercutter/reset
[MQTT] Heartbeat: {"online":true,...} -> OK
...
[LaserTracker] SessionEnd: gesamt=35s netto=15s sessionNetSec=15 total=0.58min
[I][TEST-MQTT] SessionEnd -> publishSession (lastSession=15s)
[MQTT] publishSession: {"session_minutes":1,"session_seconds":15,"freetime_s":20,"ip":"192.168.x.x"} -> OK
```
### Checkliste
| Pruefpunkt | Erwartung | Ergebnis |
|---|---|---|
| Verbindung zu mqtt.majufilo.eu | `[MQTT] Verbunden!` im Serial | [x] |
| Heartbeat beim Connect | `lasercutter/status` retained im MQTT Explorer | [x] |
| Heartbeat alle 60 s | Topic aktualisiert sich periodisch | [x] |
| Session-Publish nach Session-Ende | `lasercutter/session` mit `session_minutes`, `session_seconds` | [x] |
| Gratis-Session publiziert NICHT | kein Topic-Update bei lastSession=0 | [ ] |
| Reset via MQTT (`lasercutter/reset` = `{"reset":true}`) | `total_min` springt auf 0 | [x] |
| LWT `{"online":false}` nach Verbindungsabbruch | Nach 60 s im MQTT Explorer sichtbar | [x] |
| MQTT-Error Modul 5 bei Verbindungsverlust | `E` auf Display Modul 5 | - ungetestet - |
| Reconnect nach WiFi-Ausfall | Automatisch nach <= 10 s | - ungetestet - |
---
## Test 7.7 - WebServer (`test_web_server.cpp`)
### Zweck
Alle HTTP-Routen des `WebServerManager` im Browser pruefen: Statusseite, Konfigurationsformular (NVS), Session-Reset und ElegantOTA.
### Flash & Monitor
```bash
pio run -e test-web --target upload
pio device monitor -e test-web
```
### Vorbereitung
IP-Adresse aus dem Serial Monitor ablesen (erscheint nach WiFi-Connect):
```
[I][TEST-WEB] Browser: http://192.168.x.x/
```
### Testablauf
**A) Statusseite `GET /`:**
1. Browser oeffnen: `http://<IP>/`
2. Folgende Felder pruefen:
- Summe Session-Minuten, Maschinenlaufzeit (gesamt), letzte Laserzeit
- IP-Adresse und MQTT-Status (verbunden/getrennt)
- Broker-Hostname und Gratiszeit
3. Seite aktualisiert sich automatisch alle 10 s
4. GPIO 4 Taste betaetigen -> Session-Minuten aendern sich
**B) Konfigurationsformular `GET /config` + `POST /config`:**
1. Browser: `http://<IP>/config`
2. Felder pruefen: Broker, Port, User, Passwort, Gratiszeit-Slider, Polaritaet-Radio
3. Gratiszeit auf z.B. 30 s aendern und "Speichern" klicken
4. Serial: `[WebServer] Konfiguration gespeichert`
5. ESP32 neu starten -> Serial zeigt `gratisSeconds: 30` -> NVS-Persistenz bestaetigt
6. Config-Seite: Wert auf 20 s zuruecksetzen
**C) Session-Reset `POST /reset`:**
1. Auf Statusseite: Button "Session zuruecksetzen" klicken
2. Browser-Bestaetigung (`confirm`-Dialog) bestaetigen
3. Statusseite zeigt `Session: 0 min`
4. Gesamtzeit (NVS) **bleibt unveraendert**
5. Serial: `[WebServer] Session zurueckgesetzt`
**D) ElegantOTA `GET /update`:**
1. Browser: `http://<IP>/update`
2. ElegantOTA-Seite erscheint
3. (Optional) Test-Firmware hochladen und Neustart beobachten
**E) HTTP-Basic-Auth:**
1. In `/config` Abschnitt "Web-Zugang": Passwort setzen (z.B. `geheim`) und speichern
2. ESP32 neu starten
3. Browser: `http://<IP>/` → Browser-Login-Dialog erscheint
4. Benutzername `admin`, Passwort `geheim` eingeben → Zugang gewährt
5. Falsches Passwort eingeben → Browser zeigt 401 / erneuten Dialog
6. In `/config` Passwort wieder leeren → nach Neustart kein Schutz mehr
### Checkliste
| Pruefpunkt | Erwartung | Ergebnis |
|---|---|---|
| Statusseite erreichbar | HTML mit Session, Gesamtzeit, IP | [ ] |
| MQTT-Status korrekt | "verbunden" oder "getrennt" | [ ] |
| Auto-Reload alle 10 s | Seite aktualisiert sich | [ ] |
| Config-Formular laden | Aktuelle NVS-Werte vorbelegt | [ ] |
| Gratiszeit aendern + speichern | NVS-Wert nach Neustart korrekt | [ ] |
| Polaritaet aendern + speichern | NVS-Wert nach Neustart korrekt | [ ] |
| Session-Reset per Browser | Session = 0 min, Gesamtzeit (NVS) unveraendert | [ ] |
| `/update` erreichbar | ElegantOTA-Seite erscheint | [ ] |
| Passwort setzen + Neustart | Browser-Login-Dialog erscheint | [ ] |
| Korrektes Passwort | Zugang gewaehrt | [ ] |
| Falsches Passwort | 401 / erneuter Dialog | [ ] |
| Passwort leeren + Neustart | Kein Login-Dialog | [ ] |
---
## Gesamt-Testergebnisse
| Test | Environment | Status | Anmerkung |
|------|----------------------|-----------|-------------------------------------------------------------------|
| 1.4 | `test-display` | OK | GENERIC_HW, 90 Grad CCW Rotation, externes 5V-Netzteil |
| 1.5 | `test-button` | OK | LOW_ACTIVE, Debounce 50 ms |
| 2.2 | `test-nvs` | OK | Alle NVS-Felder, Roundtrip, Persistenz, Reset |
| 3.3 | `test-wifi` | OK | Captive Portal, Credentials-Persistenz, Reconnect |
| 4.3 | `test-display-mgr` | OK | Alle show*-Methoden, Modul-Mapping, Fehler-Indikatoren |
| 5.6 | `test-laser-tracker` | OK | Session-Logik, Gratiszeit, Summe Session/NVS-Trennung, Reset |
| 6.5 | `test-mqtt` | OK | mqtt.majufilo.eu TLS:8883, publishSession, Heartbeat, Reset-Subscribe |