6.9 KiB
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:
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:
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)
- Service-Teil komplett entfernen (nur iBeacon-Advertising, keine Verbindungen)
- Festes Advertising-Intervall setzen (100ms)
- TX-Power explizit auf Maximum fixieren
- SignalPower im iBeacon-Paket kalibrieren (RSSI @ 1m messen)
- Flags auf 0x06 ändern
- Light-Sleep für Akkubetrieb implementieren
- Alpha-Wert in CLAUDE.md korrigieren (0.15 statt 0.25)