LED-Modul
Das LED-Modul (de.profipos.ledmodul, ESP32 / Arduino / PlatformIO) ist
ein headless IoT-Knoten mit WS2812-Statusanzeige + bis zu 8 potential-freien
Relais. Live-Firmware seit 13.06.2026: Jenkins #20 (Version 6.0.20),
Commit 57cdfb7 — alle 3 Build-Envs grün.
Build-Varianten
| Env | Board | Ethernet | LED | Relais |
|---|---|---|---|---|
esp32-poe | ESP32-WROOM-32E + W5500 | ja (HSPI) | GPIO 4 | 18,19,23,25,26,27,32,33 |
esp32-s3-poe | ESP32-S3-DevKitC-1 + W5500 | ja | GPIO 4 | 1,2,42,41,40,39,38,37 |
esp32-wifi-dev | ESP32-WROOM-32 | nein (Wi-Fi) | GPIO 4 | 18,19,23,25,26,27,32,33 |
Artefakte (jeweils ca. 1,0–1,1 MB):
profipos-ledmodul-esp32-poe-6.0.20.bin
profipos-ledmodul-esp32-s3-poe-6.0.20.bin
profipos-ledmodul-esp32-wifi-dev-6.0.20.bin
Bootstrap
MQTT-Topic-Schema
Basis: profipos/<mandant>/<standort>/...
| Topic | Richtung | Payload |
|---|---|---|
anzeige/setze_status/<geraet_uuid> | in | {"status":"offen|wartet|geschlossen|pause|wartung"} |
anzeige/setze_animation/<geraet_uuid> | in | {"modus":"aus|statisch|blinken|pulsieren|lauflicht","geschwindigkeit_ms":500} |
anzeige/konfiguration/<geraet_uuid> | in (retained) | {"helligkeit_tag":180,"helligkeit_nacht":60,"nacht_von":"22:00","nacht_bis":"06:00"} |
relais/<geraet_uuid>/<n> | in | {"zustand":true} |
befehle/<geraet_uuid>/ota_starten | in | {"url":"https://...","sha256":"hex64"} |
heartbeat/<geraet_uuid> | out (retained, 30 s) | {"rssi":-65,"uptime_s":1234,"ip":"10.x.x.x","relais":[true,false,...]} |
status/<geraet_uuid> | out (LWT, retained) | {"online":false} |
log/<geraet_uuid>/info|error | out | Text |
Animations-Modi
| Modus | Wirkung |
|---|---|
aus | LEDs aus |
statisch | Volle Status-Farbe |
blinken | Hartes On/Off mit geschwindigkeit_ms |
pulsieren | Sinus-Helligkeit |
lauflicht | Rotierender Punkt |
Plus: Tag/Nacht-Helligkeit-Switch + sanfter Crossfade beim Status-Wechsel.
Status-Farben (Default, RGB hex)
| Status | Farbe |
|---|---|
offen | #00FF00 (grün) |
wartet | #FFA500 (orange) |
geschlossen | #FF0000 (rot) |
pause | #FFFF00 (gelb) |
wartung | #FF00FF (magenta) |
Überschreibbar per Captive-Portal oder via
anzeige/konfiguration/<uuid>.
NVS-Keys
Namespace profipos (15-Zeichen-Limit beachtet):
wifi_ssid, wifi_pw
mqtt_host, mqtt_port, mqtt_user, mqtt_pass, mqtt_pref
geraet_uu, led_anzahl
h_tag, h_nacht, n_von, n_bis
rp_0 .. rp_7 # uint8, 0xFF = ungenutzt
f_offen, f_wartet, f_geschlossen, f_pause, f_wartung # uint32 RGB
OTA-Update
Captive-Portal-Flow
Bei leerem/ungültigem NVS startet das Modul einen Access Point
ProfiPOS-LED-<XXXXXX> (letzte 6 MAC-Hex). Über http://192.168.4.1 ist
ein HTML-Formular für:
- WLAN-SSID + Passwort
- MQTT-Host/Port/User/Pass/Präfix
- Geräte-UUID
- Helligkeit Tag/Nacht
- Relais-Pins
- Status-Farben
Nach „Speichern“ → NVS schreiben + Reboot → Modul versucht Verbindung.
Hardware-TODOs
- esp32-poe: LED-Pin (GPIO 4) und W5500-INT (GPIO 4) kollidieren — beim Bestücken eine der Pins umlegen (z. B. INT → GPIO 35, LED bleibt GPIO 4). Aktuelle Default-Kombi nur ohne INT (Polling-Mode) benutzbar.
- esp32-poe + Relais: GPIO 18/19/23 sind VSPI-Defaults — W5500 fährt auf HSPI, also keine direkte Kollision. Falls jemand W5500 auf VSPI legt → Relais umkonfigurieren.
- esp32-s3-poe: GPIO 1/2 sind teils Strapping-Pins. Wenn Relais beim Boot auf LOW gezogen wird, Boot-Mode prüfen. Alternativ Relais auf GPIO 4–9 + 42–47 legen.
- WS2812B-Pegelwandler: ESP32 3,3 V → Stripe 5 V. Bei Strips > 30 LEDs einen 74AHCT125 vorsehen.
- Captive-Portal-Reset-Knopf: noch nicht implementiert — soll in Hardware einen GPIO auf GND ziehen können → Firmware muss bei Boot diesen Pin prüfen und bei LOW NVS leeren. Sprint Welle 3 TODO.
Build-Quirk: FastLED-Pin-Konstante
// FALSCH: switch(pin) instanziiert ALLE Template-Varianten
// → static_assert(FastPin<DATA_PIN>::validpin()) bricht ab.
// RICHTIG:
FastLED.addLeds<WS2812B, CONFIG_PROFIPOS_LED_PIN, GRB>(leds, num);
CONFIG_PROFIPOS_LED_PIN kommt als Compile-Time-Define aus
platformio.ini pro Env. Runtime-Pin-Wechsel ist nicht möglich.
ArduinoJson v7 Deprecations
// alt (Warnings): doc.containsKey("x") doc.createNestedArray("x")
// neu: doc["x"].is<JsonObject>() doc["x"].to<JsonArray>()
Verwandte Themen
- MQTT-Topics
- Geräte-Pairing (Stufe-2-Headless)
- Datenflüsse