Files
Claude-Test-App/ESP32-Code-Analyse.md

162 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ESP32 iBeacon Code-Analyse
Analyse des ESP32-Codes (`ESP32_iBeacon/ESP32_iBeacon.ino`) auf mögliche Ursachen
für instabile RSSI-Messwerte in der Android-App.
Datum: 2026-02-09
---
## Quelle: Gemini-Analyse
Die folgenden Probleme wurden von Google Gemini identifiziert:
### 1. KRITISCH: Advertising-Konflikt zwischen Service und iBeacon
**Gemini-Befund:** `init_service()` und `init_beacon()` überschreiben sich gegenseitig
das Advertising-Paket. `init_service()` startet Advertising mit Service-UUID, dann
stoppt `init_beacon()` alles und überschreibt es mit iBeacon-Daten. Das Service-Advertising
geht verloren. Beim Reconnect nach Disconnect wird `pAdvertising->start()` aufgerufen,
aber es ist unklar, welche Advertising-Daten dann aktiv sind.
**Gemini-Empfehlung:** Kombinierte Funktion nutzen, die iBeacon-Daten ins Haupt-Paket
und die Service-UUID ins Scan-Response-Paket legt.
**Eigene Einschätzung:** Bestätigt. Im Code wird in Zeile 78 (`init_service`) Advertising
gestartet, in Zeile 85 (`init_beacon`) sofort wieder gestoppt und neu konfiguriert.
Das ist zwar für den reinen iBeacon-Betrieb kein Problem (das letzte Paket gewinnt),
aber der `onDisconnect`-Callback (Zeile 29) startet Advertising erneut, ohne die
iBeacon-Daten neu zu setzen. Nach einer Verbindung könnten also fehlerhafte
Advertising-Pakete gesendet werden.
### 2. HOCH: Kein explizites Advertising-Intervall gesetzt
**Gemini-Befund:** Ohne explizites Intervall nutzt der ESP32 den BLE-Stack-Default.
Unregelmäßige Pakete führen zu variierenden Abtastraten auf der Android-Seite und
damit zu instabilen RSSI-Werten.
**Gemini-Empfehlung:** Festes Intervall von 100ms setzen:
```cpp
pAdvertising->setMinInterval(0xA0); // 160 * 0.625ms = 100ms
pAdvertising->setMaxInterval(0xA0);
```
**Eigene Einschätzung:** Bestätigt und sehr relevant. Der Default-Intervall liegt
typischerweise bei 100-1280ms, was für Indoor-Positioning zu unregelmäßig ist.
Ein festes, kurzes Intervall (100ms) sorgt für konsistente Datenrate auf der
Android-Seite. Die Android-App scannt bereits mit `SCAN_MODE_LOW_LATENCY`
(BleScanner.kt:165), profitiert aber nur davon, wenn der ESP32 auch regelmäßig sendet.
### 3. HOCH: TX-Power nicht explizit konfiguriert
**Gemini-Befund:** Die Sendeleistung wird nicht festgelegt, was zu variierender
Ausgangsleistung führen kann.
**Gemini-Empfehlung:**
```cpp
BLEDevice::setPower(ESP_PWR_LVL_P9); // +9 dBm
```
**Eigene Einschätzung:** Bestätigt. Ohne fixe TX-Power kann der ESP32 die Leistung
dynamisch anpassen. Für RSSI-basierte Distanzschätzung ist eine konstante
Sendeleistung zwingend notwendig, da die gesamte Berechnung auf dem
Log-Distance Path Loss Model basiert. Hinweis: Der Seeed XIAO ESP32-C3 unterstützt
bis zu +21 dBm – der korrekte Enum-Wert muss ggf. angepasst werden.
### 4. MITTEL: setSignalPower nicht kalibriert
**Gemini-Befund:** Der Wert `0xc5` (-59 dBm) im iBeacon-Paket ist ein Standardwert
und nicht für die verwendete Hardware kalibriert.
**Gemini-Empfehlung:** RSSI bei exakt 1m Abstand messen (60s Durchschnitt) und
den gemessenen Wert als Signed Byte in Hex setzen.
**Eigene Einschätzung:** Teilweise relevant. Der `signalPower`-Wert wird in der
Android-App aktuell nicht für die Distanzberechnung verwendet – stattdessen wird
`BeaconData.RSSI_AT_ONE_METER = -65.0` in Kotlin hardcoded (BeaconData.kt:37).
Die App liest zwar `txPower` aus dem Paket (BleScanner.kt:145), nutzt ihn aber
nicht im PositionCalculator. Trotzdem sollte der Wert korrekt sein, falls er
zukünftig genutzt wird.
### 5. MITTEL: Advertising-Flags
**Gemini-Befund:** Flags `0x1A` statt Standard-iBeacon `0x06`.
**Gemini-Empfehlung:** `0x06` verwenden (LE General Discoverable + BR/EDR Not Supported).
**Eigene Einschätzung:** Geringes Risiko. `0x1A` setzt zusätzlich das Bit für
"Simultaneous LE and BR/EDR (Controller)" – bei einem reinen BLE-Beacon unnötig,
aber in der Praxis unproblematisch. `0x06` wäre sauberer.
### 6. NIEDRIG: Manufacturer ID Byte-Order
**Gemini-Befund:** ESP32 sendet `0x004C` (Little-Endian, korrekt laut BLE-Spec).
Android-App parst mit `0x4C00`.
**Gemini-Empfehlung:** Android-App prüfen.
**Eigene Einschätzung:** Kein Problem. Android's `getManufacturerSpecificData()`
erwartet den Company Identifier in Host-Byte-Order. Der Wert `0x4C00` in der
Android-App (BeaconData.kt:12) ist korrekt für Apple's Company ID und funktioniert
nachweislich (die App empfängt ja Beacons). Die ESP32-Bibliothek übernimmt die
Konvertierung intern.
---
## Eigene Zusatzanalyse (Claude)
Über die Gemini-Analyse hinaus sind folgende Punkte aufgefallen:
### 7. HOCH: loop() sendet Notifications alle 2 Sekunden
In `loop()` (Zeile 114-123) wird bei bestehender Verbindung alle 2 Sekunden eine
Notification gesendet. Das ist für den iBeacon-Betrieb irrelevant, aber: Wenn sich
ein Gerät verbindet, könnte das Advertising unterbrochen oder verlangsamt werden.
Der ESP32 BLE-Stack kann nicht gleichzeitig eine aktive Verbindung bedienen und
mit voller Rate advertisen.
**Empfehlung:** Für reinen Beacon-Betrieb den gesamten Service-Teil entfernen
(init_service, MyCallbacks, MyServerCallbacks, Notification-Code in loop).
Der ESP32 soll nur advertisen, keine Verbindungen annehmen.
### 8. MITTEL: Kein Deep-Sleep / Light-Sleep zwischen Advertisements
Für Akkubetrieb fehlt jegliche Energiespar-Logik. Der ESP32 läuft permanent
im aktiven Modus, auch zwischen den Advertising-Events.
**Empfehlung:** Für den Seeed XIAO ESP32-C3 im Akkubetrieb Light-Sleep aktivieren
oder den ESP32 zwischen Advertisements in den Deep-Sleep schicken und per Timer
aufwecken.
### 9. NIEDRIG: PositionSmoother Alpha-Wert Diskrepanz
In der CLAUDE.md und im PositionSmoother-Defaultwert steht alpha=0.25, aber
in BleScanner.kt:52 wird `PositionSmoother(alpha = 0.15)` instanziiert.
Der tatsächlich verwendete Wert ist 0.15 (reaktiver als dokumentiert).
---
## Zusammenfassung: Prioritäten
| # | Priorität | Problem | Quelle |
|---|-----------|--------------------------------------|---------|
| 1 | KRITISCH | Advertising-Konflikt Service/iBeacon | Gemini |
| 2 | HOCH | Kein Advertising-Intervall gesetzt | Gemini |
| 3 | HOCH | TX-Power nicht fixiert | Gemini |
| 7 | HOCH | Verbindungen stören Advertising | Claude |
| 4 | MITTEL | SignalPower nicht kalibriert | Gemini |
| 5 | MITTEL | Advertising-Flags suboptimal | Gemini |
| 8 | MITTEL | Kein Energiesparmodus | Claude |
| 9 | NIEDRIG | Alpha-Wert Diskrepanz Doku vs Code | Claude |
| 6 | NIEDRIG | Manufacturer ID Byte-Order | Gemini |
## Empfohlene Maßnahmen (Reihenfolge)
1. Service-Teil komplett entfernen (nur iBeacon-Advertising, keine Verbindungen)
2. Festes Advertising-Intervall setzen (100ms)
3. TX-Power explizit auf Maximum fixieren
4. SignalPower im iBeacon-Paket kalibrieren (RSSI @ 1m messen)
5. Flags auf 0x06 ändern
6. Light-Sleep für Akkubetrieb implementieren
7. Alpha-Wert in CLAUDE.md korrigieren (0.15 statt 0.25)