Files
AquaMasterMQTT/CLAUDE.md
Carsten Graf 0223cceef8
Some checks failed
/ build (push) Has been cancelled
Button Simmulator, Frontend änderungen
2026-04-11 20:24:39 +02:00

5.9 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Projektüberblick

AquaMaster MQTT ist die ESP32-Firmware für die Master-Einheit eines "Aquacross / NinjaCross"-Sport-Timers (zwei Bahnen, Start/Stopp-Taster). Der Master stellt einen WiFi-AP und/oder STA bereit, hostet einen MQTT-Broker, einen Async-Webserver mit WebSocket-Live-Updates und kommuniziert mit batteriebetriebenen Funktastern. Die README.md im Repo-Root ist veraltet/falsch (Gitea-MCP-Text) — als Quelle für Projektkontext stattdessen API.md, TODO.md, Bedienungsanleitung_NinjaCross_Timer.html und den Code selbst nutzen.

Build & Flash (PlatformIO)

Default-Environment ist esp32thing_CI (siehe platformio.ini). Weitere Envs: wemos_d1_mini32, esp32thing, esp32thing_OTA (OTA an 192.168.1.96), um_feathers3, um_feathers3_debug.

pio run                              # Default-Env bauen
pio run -e esp32thing                # Spezifisches Env
pio run -e esp32thing -t upload      # Flashen
pio run -e esp32thing -t buildfs     # SPIFFS-Image aus data/ bauen
pio run -e esp32thing -t uploadfs    # SPIFFS flashen (data/ → ESP)
pio device monitor -b 115200         # Serieller Monitor
pio run -e esp32thing_OTA -t upload  # OTA-Upload (Ziel-IP in platformio.ini)

Tests gibt es nicht — test/ enthält nur ein leeres README.

CI

.github/workflows/build.yml baut bei jedem Push firmware.bin und spiffs.bin mit pio run -e esp32thing_CI und erzeugt automatisch ein GitHub-Release mit Tag esp32thing-<datum>-<sha7>. Wenn der Build lokal funktioniert, aber CI nicht, ist esp32thing_CI (board=esp32dev, platform=espressif32) die maßgebliche Konfiguration.

Architektur (das Wesentliche)

Header-only-Pattern (wichtig!)

Es gibt nur eine .cpp-Datei: src/master.cpp. Alle anderen Module unter src/*.h enthalten sowohl Deklarationen als auch Implementierungen und definieren teilweise globale Objekte (z. B. AsyncWebServer server(80) in webserverrouter.h, Preferences preferences in licenceing.h, PicoMQTT::Server mqtt in communication.h). Konsequenzen:

  • Jeder dieser Header darf nur in master.cpp inkludiert werden, sonst gibt es Multiple-Definition-Linkerfehler.
  • Header inkludieren sich gegenseitig (master.hwebserverrouter.hcommunication.h). Beim Hinzufügen neuer Header die bestehende Include-Reihenfolge in master.cpp beibehalten.
  • Globale Timer-/Button-State-Variablen (timerData1, timerData2, buttonConfigs, localTimes, learningMode, gamemode, …) leben in src/master.h und werden überall direkt referenziert.

Wer eine neue Datei anlegt: entweder als weiteren Header dem Pattern folgen und in master.cpp einklinken, oder bewusst eine echte .cpp mit extern-Deklarationen erstellen.

Laufzeit-Module

  • master.cppsetup()/loop(). Reihenfolge in setup() ist relevant (SPIFFS → API-Setups → load*() aus Preferences → WiFi → OTA → Routes → WebSocket → MQTT → RFID). loop() priorisiert MQTT vor WebSocket vor RFID.
  • communication.h — PicoMQTT-Broker. Tasten publishen auf aquacross/button/<MAC>; readButtonJSON() parst, ordnet die MAC einer der vier Rollen (start1/stop1/start2/stop2) zu und triggert die Timerlogik. Hält pro MAC TimestampData für Drift-Berechnung.
  • webserverrouter.hESPAsyncWebServer auf Port 80 + WebSocket /ws. Liefert statische Seiten aus SPIFFS (/, /settings, /leaderboard, /rfid) und alle /api/...-Endpunkte. Vollständige Routenliste in API.md.
  • wificlass.h — AP-Modus auf 192.168.10.1 (eindeutiger SSID-Suffix), STA-Fallback wenn gespeicherte Credentials vorhanden. Bindet PrettyOTA (lokale Bibliothek unter lib/PrettyOTA/) und mDNS ein.
  • preferencemanager.h — Persistierung in NVS (Preferences). Namespaces u. a. buttons, leaderboard, plus WiFi-/Location-/Settings-Slots. Beim Ändern persistierter Strukturen (z. B. ButtonConfigs) auf Größenkompatibilität achten — loadButtonConfig() lädt nur, wenn getBytesLength == sizeof(buttonConfigs).
  • licenceing.h — HMAC-SHA256 (mbedtls) gegen secret über die STA-MAC; bestimmt Tier/Online-Funktionen. Lizenz wird zusammen mit jeder Backend-Anfrage als Authorization: Bearer … gesendet.
  • databasebackend.h — HTTPS-Client gegen https://ninja.reptilfpv.de (Locations, Leaderboard-Upload, Health). Funktioniert nur bei verbundenem STA + gültiger Lizenz.
  • rfid.h — Adafruit PN532 (I²C/SPI). Liest UIDs nur, wenn isRFIDReadingActive(); UID landet in TimerData*::RFIDUID und wird mit Namen aus localUsers/Backend verknüpft.
  • gamemodes.h — Modus 0=individual, 1=wettkampf; steuert, wann Timer als „bereit/armiert/laufend" gilt und wie Bestzeiten abgelegt werden (lokales localTimes-Vektor + optional Backend).
  • timesync.h/debug.h/statusled.h/battery.h/buttonassigh.h/helper.h — Hilfsmodule (NTP/Zeitzone, Debug-API, Status-LED, Akku, Lerne-Mode für Tasten-Zuordnung).

Web-Frontend

data/ enthält index.html, settings.html, leaderboard.html, rfid.html plus zugehörige CSS und ein pictures/-Verzeichnis. Diese Dateien werden via pio run -t uploadfs ins SPIFFS geschrieben und vom Webserver direkt ausgeliefert. Frontend-Änderungen erfordern ein erneutes uploadfs — ein normaler Firmware-Upload aktualisiert sie nicht.

data/firmware.bin wird unter /firmware.bin ausgeliefert (Buttons können sich darüber selbst aktualisieren).

API

Vollständige HTTP-/WebSocket-API in API.md (autoritativ; apientpoints ist eine ältere Kurzversion). Alle POST-Routen erwarten Form-Parameter, kein JSON-Body. Antworten sind JSON, außer bei statischen Dateien.

Sprache

Code-Kommentare und einige Variablennamen sind deutsch (bahn, wettkampf, „Anlernmodus"). Beim Erweitern bei der vorhandenen Sprache bleiben statt halb zu übersetzen.