docs(readme): README auf Phase-5-Stand aktualisiert, Tests-Sektion ergaenzt

This commit is contained in:
MaPaLo76 2026-02-22 19:14:15 +01:00
parent bf1b32e24d
commit d5d0085d93
2 changed files with 179 additions and 42 deletions

217
README.md
View File

@ -19,7 +19,8 @@ Dieses Projekt implementiert einen ESP32-basierten MQTT-Client mit Dot-Matrix-Di
11. [Fehlerverhalten](#fehlerverhalten)
12. [Bibliotheken](#bibliotheken)
13. [Build & Flash](#build--flash)
14. [Beitragen / Commits](#beitragen--commits)
14. [Tests](#tests)
15. [Beitragen / Commits](#beitragen--commits)
---
@ -101,17 +102,19 @@ Es ist in **zwei Zonen** aufgeteilt, die unabhängig voneinander beschrieben wer
> **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
### Modul-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 `---` |
| Modul(e) | 0-Index | Physisch | Anzeige-Inhalt |
|----------|---------|-------------------|---------------------------------------------------------------|
| 0 | 0 | Oben links | **WiFi-Fehler** (`E` = kein WLAN, leer = OK) |
| 13 | 13 | Oben Mitterechts | **Session-Minuten** ganzzahlig (0 bei Neustart, RAM-only) |
| 4 | 4 | Unten links | **MQTT-Fehler** (`E` = kein Broker, leer = OK) |
| 57 | 57 | Unten Mitterechts| **Countdown** (Gratiszeit in Sek.) oder `--` (Idle/Netto) |
- 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`
- Session-Minuten (Module 13) 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)
---
@ -128,11 +131,45 @@ Der potentialfreie Ausgang des Laser Cutters (z.B. Schließer-Kontakt über Opto
## 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.
### Zwei getrennte Zeitkreise
| Kreis | Speicher | Reset | Verwendung |
|---|---|---|---|
| **Session-Minuten** | RAM | bei Neustart / `resetSession()` | Display Module 13 |
| **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: 0120 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.
---
@ -222,35 +259,35 @@ Firmware-Updates können kabellos über die Weboberfläche unter `/update` einge
## 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/`---`) | |
| 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_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 |
| 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
# PlatformIO CLI
pio run --target upload
# Haupt-Firmware bauen und flashen
pio run -e az-delivery-devkit-v4 --target upload
# Serieller Monitor
pio device monitor
@ -265,21 +302,119 @@ Ziel-Board: `az-delivery-devkit-v4` (ESP32), Upload-Port: `COM3`
```
MQTT-Display-LaserCutter/
├── src/
│ └── main.cpp # Hauptprogramm
│ ├── 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
├── 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
│ ├── 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
├── 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 |
### 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 13 (ganze Minuten: 0, 1, 42, 999)
- `showMqttError(true/false)` → Modul 4
- `showCountdown(n)` → Module 57
- `showIdle()` → Module 57 (`--`)
### 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 13 | Module 57 | Serial |
|---|---|---|---|
| Idle | `0` | `--` | |
| Laser an (020 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.
---
## Beitragen / Commits
Dieses Projekt verwendet **[Conventional Commits](https://www.conventionalcommits.org/)** für alle Git-Commit-Nachrichten.

View File

@ -43,6 +43,7 @@ void setup() {
Serial.println("========================================");
settings.begin();
settings.saveGratisSeconds(DEFAULT_GRATIS_SECONDS); // NVS-Korrektur: setzt 20s
settings.printToSerial();
display.begin();
@ -98,7 +99,8 @@ void loop() {
bootPressedAt = millis();
Serial.println("[BTN] BOOT gedrueckt - 3s halten fuer Reset...");
} else if ((millis() - bootPressedAt) >= RESET_HOLD_MS) {
Serial.println("[RESET] Gesamtzeit wird zurueckgesetzt!");
Serial.println("[RESET] Alle Einstellungen + Gesamtzeit werden zurueckgesetzt!");
settings.reset(); // NVS komplett auf Defaults (inkl. gratisSeconds=20)
laserTracker.resetTotal();
display.showLaserTime(0.0f);
display.showIdle();