6.8 KiB
Gemini-Delegator Memory
Bug-Patterns
State-Initialisierung bei Scan-Start
Problem identifiziert: In BleScanner wurde PositionCalculator nur beim startScanning() initialisiert. Config-Änderungen während eines laufenden Scans wurden nicht übernommen.
Lösung: Extrahiere Initialisierungs-Logik in separate Methode (initializePositionCalculator()), biete öffentliche reloadConfig() Methode an. UI ruft diese nach Config-Änderung auf.
Pattern: Bei Langlebigen Objekten (Scanner) die State von kurzlebiger Config abhängt → Reload-Mechanismus vorsehen.
KeyboardType für negative Zahlen
Problem: KeyboardType.Decimal und KeyboardType.Number erlauben in Android Compose kein Minuszeichen.
Lösung: KeyboardType.Text für Felder verwenden, die negative Werte akzeptieren müssen (Koordinaten, RSSI). Validierung via toDoubleOrNull() bleibt bestehen.
Betroffene Felder: Beacon-Koordinaten (X/Y), Raum-Positionen (X/Y), RSSI-Werte (immer negativ).
Hardware-Debugging
BLE-Unsichtbarkeit (ESP32 + Android)
Problem: Ein spezifischer ESP32-C3 wird auf einem spezifischen Android-Handy NICHT gefunden (auch nicht mit nRF Connect), auf anderen Handys aber schon. Andere ESP32s funktionieren auf dem problematischen Handy.
Ursache (wahrscheinlich): MAC-Adress-Kollision oder Android BLE-Controller-Blacklisting auf Hardware-Level.
Diagnose-Schritte:
- Original BLE-MAC auslesen (
esp_bt_dev_get_address()nachBLEDevice::init()) - Mit MAC auf funktionierendem Handy (nRF Connect) vergleichen
- Custom-MAC setzen via
esp_base_mac_addr_set()VORBLEDevice::init()
Lösung: Custom-MAC flashen mit locally administered Address (Byte 0 = 0x02), eindeutige Werte wählen.
Code-Pattern (ESP32):
#include "esp_bt_device.h" // Für MAC-Ausgabe
#include "esp_mac.h" // Für MAC-Setzen
uint8_t custom_mac[6] = {0x02, 0xAA, 0xBB, 0xCC, 0xDD, 0x05};
esp_base_mac_addr_set(custom_mac); // VOR BLEDevice::init()
BLEDevice::init("Name");
const uint8_t* ble_mac = esp_bt_dev_get_address(); // Ausgeben
Quellen: Random Nerd Tutorials, Nordic DevZone BLE Invisibility
Projekt-Spezifisches
BLE Indoor Positioning App
- Aktive Version:
/App v2/(vorher/App v1_2/) - Config-Persistierung: SharedPreferences via
ConfigRepository - Datenfluss: ConfigRepository → BleScanner → PositionCalculator → UI
- Keine DI: Direkte Instanziierung, StateFlow für Reaktivität
- Sprache: Kotlin, Compose UI, Kommentare auf Deutsch
- Koordinaten: Beliebige Werte möglich (auch negativ) – Bounding Box wird aus Räumen + Beacons berechnet
Kritische Klassen
BleScanner: Zentrale BLE-Logik, verwaltet Scanner, Filter, Calculator, SmootherPositionCalculator: Trilateration (IDW + Gauss-Newton + Blending)ConfigRepository: Lädt/Speichert AppConfig (Raumgröße + Beacon-Positionen)BeaconFilterManager: Verwaltet RSSI-Filter pro Beacon (Kalman/EMA/MA)
Häufige Fehlerquellen
- Config-Änderungen während laufender Operationen
- Initialisierung nur bei Start ohne Reload-Mechanismus
- Fehlende Synchronisation zwischen UI-State und Scanner-State
Config-Modell Pattern (erweitert)
Gelernt bei: Individuelle pathLossExponent + rssiAtOneMeter pro Beacon
@Serializable data classmit Default-Werten → Abwärtskompatibilität (alte Configs ohne neue Felder laden mit Defaults)- Neue Felder in beiden Dialogen:
- AddBeaconDialog: Neue Beacons (Default-Werte vorbelegen:
mutableStateOf("5.5")) - EditBeaconDialog: Bearbeitung (beacon.field.toString() initialisieren)
- AddBeaconDialog: Neue Beacons (Default-Werte vorbelegen:
- Config-Anzeige: LazyColumn erweitern (neue Felder anzeigen)
- Beacon-Liste klickbar:
.clickable { showEditBeaconDialog = beacon } - Berechnungs-Methoden: Per-Beacon-Lookup mit Fallback →
beacons.find { it.minor == beaconMinor }?.field ?: globalDefault
Gemini-Interaktion
Rate Limits
Gemini: 429 RESOURCE_EXHAUSTED möglich, liefert oft trotzdem Ergebnisse nach Retries (am Ende der Ausgabe).
Gemini Prompt Best Practices
- Kontext vollständig angeben (relevante Code-Ausschnitte mit Line-Nummern)
- Aufgabe strukturiert (nummeriert), Dateipfade explizit
- Output-Format: "OUTPUT ONLY unified diff, no explanations"
Wann selbst fixen vs. Gemini
- Selbst: Klare Anforderung, minimale Änderung (z.B. KeyboardType-Wechsel)
- Gemini: Große Refactorings, komplexe Algorithmen
- Nach Gemini: IMMER fachlich prüfen (Typ, Logik, Patterns)
Gemini Fehler-Pattern
Problem: Gemini generiert Diffs mit falschen Annahmen über Datenstrukturen
- Beispiel (2026-02-10): Negative Koordinaten – Gemini verwendete
.corners(nicht existent) statt.x/.y/.width/.height - Lösung: Bei strukturellen Änderungen (Datenmodell, API) relevante Klassen vollständig in Prompt inkludieren
- Warnung: Gemini erfindet manchmal Pfade (
com.examplestattcom.erik) → Diff-Pfade immer prüfen
Color-Parameter in @Composable mit Canvas (2026-02-10)
Problem: Gemini versuchte beaconColor: Color = MaterialTheme.colorScheme.primary als Default-Parameter in Funktionssignatur zu setzen – funktioniert NICHT, da kein @Composable-Context in Parameter-Defaults verfügbar ist.
Lösung: Color-Parameter MIT Defaults direkt in der @Composable-Funktion deklarieren (wo MaterialTheme verfügbar ist). Bei Helper-Funktionen (z.B. drawRooms) Parameter ohne Defaults durchreichen.
Korrektur: Nach Gemini-Output selbst gefixt – Color-Parameter in FloorplanView mit MaterialTheme-Defaults versehen, drawRooms()-Signatur manuell erweitert.
Material Icons Verfügbarkeit (2026-02-10)
Problem: Gemini generiert oft nicht-existierende Material Icons (z.B. DarkMode, LightMode, Brightness4, Brightness7, Nightlight, WbSunny).
Lösung: Nach Gemini-Output IMMER Icon-Verfügbarkeit prüfen:
- Nur Icons aus
Icons.Default.*verwenden, die in bestehenden Dateien bereits verwendet werden (z.B.Settings,Place,Info) - Falls spezielle Icons benötigt werden: Im Projekt nach verwendeten Icons greppen (
Icons\.Default\.) - Fallback: Generische Icons wie
Info,Check,Starverwenden
Warnung: Icons.Outlined/Icons.Filled sind oft nicht vollständig in älteren Material Icons Versionen verfügbar.
remember() außerhalb @Composable (2026-02-10)
Problem: Gemini verwendete var isDarkMode by remember { mutableStateOf(...) } in MainActivity.onCreate() – remember funktioniert NICHT außerhalb von @Composable Funktionen.
Lösung: Direkt mutableStateOf() als Property verwenden (private var isDarkMode by mutableStateOf(false)) oder rememberSaveable INNERHALB setContent { } Block nutzen.