# 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:///` 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:///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:///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:///` → 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 |