Bluetooth Funktionalität #8

Open
opened 2026-08-28 10:28:26 +02:00 by erdbruegger · 7 comments
Owner

Wir hatten in folgendem Repo (Link) bereits einen ersten funktionierenden Prototypen gebaut, der die Steuerbefehle per BLE an das Auto sendet .

Können wir diese Funktion in dieser App integrieren? Aktuell schicken wir die Befehle ans Backend und sie landen dort in einer Queue. Könnte man den Mechanismus bei behalten, aber die Logik so ändern, dass er auch eine lokale Queue in der App hält und erstmal versucht das Command per BLE abzuschicken ? (Scan der Umgebung, wird AICHI_* gefunden? Falls ja versuch execute, falls nein, ab ans Backend). Sollte der BLE gefunden werden, aber ein Fehler auftreten, ebenfalls als Backup das Command ans Backend schicken

Wir hatten in folgendem Repo ([Link](https://forgejo.timo-erdbruegger.de/aiways/BLEAndroidApp)) bereits einen ersten funktionierenden Prototypen gebaut, der die Steuerbefehle per BLE an das Auto sendet . Können wir diese Funktion in dieser App integrieren? Aktuell schicken wir die Befehle ans Backend und sie landen dort in einer Queue. Könnte man den Mechanismus bei behalten, aber die Logik so ändern, dass er auch eine lokale Queue in der App hält und erstmal versucht das Command per BLE abzuschicken ? (Scan der Umgebung, wird AICHI_* gefunden? Falls ja versuch execute, falls nein, ab ans Backend). Sollte der BLE gefunden werden, aber ein Fehler auftreten, ebenfalls als Backup das Command ans Backend schicken
Collaborator

Umgesetzt (Release v1.0.28, Commit 82ce396). CI + Deploy grün.

Der Weg eines Befehls ist jetzt genau der aus Deinem Issue:

  1. Bluetooth zuerst — Scan nach AICHI_*. Gefunden → A001-Auth → B001-Befehl → resCode 0. Damit ist der Befehl sofort ausgeführt, ganz ohne Netz.
  2. Kein Fahrzeug in Reichweite → ab ans Backend, wie bisher.
  3. Gefunden, aber Fehler (Auth abgelehnt, Timeout, resCode != 0) → ebenfalls ans Backend, genau wie von Dir gewünscht.
  4. Geht auch das nicht (offline) → der Befehl bleibt in einer lokalen, persistenten Warteschlange und wird beim nächsten App-Start oder per „Erneut versuchen" nachgereicht. Er geht also nicht mehr verloren, wenn das Backend gerade weg ist.

Eine Entscheidung, die Du kennen solltest: Was per Bluetooth ausgeführt wurde, geht nicht zusätzlich ans Backend. Sonst würde das Auto denselben Befehl später ein zweites Mal ausführen, sobald es wieder online ist. Nebenwirkung: per BLE ausgeführte Befehle tauchen nicht in der Backend-Historie („Letzte Befehle") auf. Wenn Du die Historie vollständig haben willst, wäre der saubere Weg ein Backend-Endpunkt „bereits am Auto ausgeführt" — sag Bescheid, dann lege ich dafür ein Issue im Backend an.

Zur Portierung: Krypto und Protokoll sind aus aiways/BLEAndroidApp nach Dart übertragen (AES-128-CBC, RSA-1024 PKCS#1, MD5, V1-Frames). Ich habe aus Deinem Java-Prototyp mit festen tid/date Referenzvektoren erzeugt und teste die Dart-Seite byte-genau dagegen — A001- und B001-Frames sind identisch zu dem, was am Auto nachweislich funktioniert. Transport über flutter_blue_plus: Scan, 20-Byte-Chunks mit Response, Frame-Reassembly, pro Befehl eine frische Verbindung — wie im Prototyp.

Befehls-Zuordnung: entriegeln/verriegeln/Heckklappe/Fenster auf+zu/Schiebedach kippen/Blinken/Hupe/Klima an+aus (mit Zieltemperatur, ×10 wie in der TBox). Nicht zugeordnet sind sunroof_open (Prototyp kennt nur „kippen" und „zu") und charge_port_open — dafür kenne ich keinen verifizierten Code, und am Fahrzeug rate ich nicht. Die beiden gehen weiterhin direkt ans Backend.

Sicherheit — bitte kurz gegenlesen: Der Community-Key liegt jetzt auch in diesem Repo. Er wird nur für Android/iOS kompiliert (bedingter Import); im Web-Bundle ist er nicht enthalten — ich habe das im ausgelieferten main.dart.js auf http://192.168.1.85/ gegengeprüft (weder Key noch OPENAIWAYS/AICHI kommen darin vor). Das war mir wichtig, weil das Web-Bundle unauthentifiziert im LAN liegt.

Was Du noch tun musst: Bluetooth wirkt nur in der Android-App, und die CI baut derzeit kein APK (BUILD_APK=false). Zum Testen am Auto bitte die Repo-Variable auf true setzen und einmal neu releasen — dann hängt das APK am Release.

Verifiziert: 37 Tests grün (Protokoll gegen die Java-Vektoren, Queue-Weichen inkl. Offline-Fall und Persistenz), flutter analyze sauber, Web- und Android-Release-Build lokal gebaut, Permissions im fertigen APK geprüft. Am echten Fahrzeug konnte ich nicht testen — das geht nur mit Handy in BLE-Reichweite.

Umgesetzt (Release `v1.0.28`, Commit `82ce396`). CI + Deploy grün. **Der Weg eines Befehls ist jetzt genau der aus Deinem Issue:** 1. **Bluetooth zuerst** — Scan nach `AICHI_*`. Gefunden → A001-Auth → B001-Befehl → `resCode 0`. Damit ist der Befehl sofort ausgeführt, ganz ohne Netz. 2. **Kein Fahrzeug in Reichweite** → ab ans Backend, wie bisher. 3. **Gefunden, aber Fehler** (Auth abgelehnt, Timeout, `resCode != 0`) → ebenfalls ans Backend, genau wie von Dir gewünscht. 4. **Geht auch das nicht** (offline) → der Befehl bleibt in einer **lokalen, persistenten Warteschlange** und wird beim nächsten App-Start oder per „Erneut versuchen" nachgereicht. Er geht also nicht mehr verloren, wenn das Backend gerade weg ist. **Eine Entscheidung, die Du kennen solltest:** Was per Bluetooth ausgeführt wurde, geht **nicht zusätzlich** ans Backend. Sonst würde das Auto denselben Befehl später ein zweites Mal ausführen, sobald es wieder online ist. Nebenwirkung: per BLE ausgeführte Befehle tauchen nicht in der Backend-Historie („Letzte Befehle") auf. Wenn Du die Historie vollständig haben willst, wäre der saubere Weg ein Backend-Endpunkt „bereits am Auto ausgeführt" — sag Bescheid, dann lege ich dafür ein Issue im Backend an. **Zur Portierung:** Krypto und Protokoll sind aus `aiways/BLEAndroidApp` nach Dart übertragen (AES-128-CBC, RSA-1024 PKCS#1, MD5, V1-Frames). Ich habe aus Deinem Java-Prototyp mit festen `tid`/`date` **Referenzvektoren erzeugt** und teste die Dart-Seite byte-genau dagegen — A001- und B001-Frames sind identisch zu dem, was am Auto nachweislich funktioniert. Transport über `flutter_blue_plus`: Scan, 20-Byte-Chunks mit Response, Frame-Reassembly, pro Befehl eine frische Verbindung — wie im Prototyp. **Befehls-Zuordnung:** entriegeln/verriegeln/Heckklappe/Fenster auf+zu/Schiebedach kippen/Blinken/Hupe/Klima an+aus (mit Zieltemperatur, ×10 wie in der TBox). **Nicht** zugeordnet sind `sunroof_open` (Prototyp kennt nur „kippen" und „zu") und `charge_port_open` — dafür kenne ich keinen verifizierten Code, und am Fahrzeug rate ich nicht. Die beiden gehen weiterhin direkt ans Backend. **Sicherheit — bitte kurz gegenlesen:** Der Community-Key liegt jetzt auch in diesem Repo. Er wird **nur für Android/iOS kompiliert** (bedingter Import); im Web-Bundle ist er nicht enthalten — ich habe das im ausgelieferten `main.dart.js` auf http://192.168.1.85/ gegengeprüft (weder Key noch `OPENAIWAYS`/`AICHI` kommen darin vor). Das war mir wichtig, weil das Web-Bundle unauthentifiziert im LAN liegt. **Was Du noch tun musst:** Bluetooth wirkt nur in der **Android-App**, und die CI baut derzeit kein APK (`BUILD_APK=false`). Zum Testen am Auto bitte die Repo-Variable auf `true` setzen und einmal neu releasen — dann hängt das APK am Release. **Verifiziert:** 37 Tests grün (Protokoll gegen die Java-Vektoren, Queue-Weichen inkl. Offline-Fall und Persistenz), `flutter analyze` sauber, Web- **und** Android-Release-Build lokal gebaut, Permissions im fertigen APK geprüft. **Am echten Fahrzeug konnte ich nicht testen** — das geht nur mit Handy in BLE-Reichweite.
Author
Owner

Ich habe den BUILD_APK enabled, um das mit BLE zu testen, kannst du noch ein mal den Build triggern?

Ich habe den BUILD_APK enabled, um das mit BLE zu testen, kannst du noch ein mal den Build triggern?
Collaborator

Build ist durch — Release v1.0.31 (Commit c42cb64), CI + Deploy grün.

Mit dem jetzt gesetzten BUILD_APK=true hängen die APKs am Release:

Der Commit ist bewusst leer — am Code hat sich nichts geändert, er stößt nur den Release-Job erneut an, damit er diesmal die APKs baut. Der BLE-Stand aus 82ce396 ist unverändert drin, dazu die zwischenzeitlichen Releases zu #6 und #3.

Gegengeprüft am fertigen APK (heruntergeladen vom Release, nicht lokal gebaut): BLUETOOTH_SCAN (neverForLocation), BLUETOOTH_CONNECT, für Android ≤ 11 zusätzlich BLUETOOTH/BLUETOOTH_ADMIN/ACCESS_FINE_LOCATION, dazu INTERNET. Web läuft weiter unter http://192.168.1.85/ (HTTP 200).

Für den Test am Auto: Beim ersten Befehl fragt Android nach der Bluetooth-Berechtigung — die braucht es, sonst findet der Scan nichts. Wenn ein Befehl per BLE durchgeht, siehst Du ihn nicht in der Backend-Historie „Letzte Befehle"; das ist so gewollt (sonst führt das Auto ihn später ein zweites Mal aus). Nicht per BLE belegt sind weiterhin sunroof_open und charge_port_open — die laufen über das Backend.

Falls am Fahrzeug etwas hakt: sag mir bitte, welcher Befehl und was die App anzeigt (Timeout, Auth abgelehnt, oder „ans Backend geschickt"), dann kann ich das gezielt eingrenzen.

Build ist durch — **Release `v1.0.31`** (Commit `c42cb64`), CI + Deploy grün. Mit dem jetzt gesetzten `BUILD_APK=true` hängen die APKs am Release: - [aiways-app-v1.0.31-arm64-v8a.apk](https://forgejo.timo-erdbruegger.de/aiways/AiwaysApp/releases/download/v1.0.31/aiways-app-v1.0.31-arm64-v8a.apk) — 19,5 MB, das ist das richtige für praktisch jedes aktuelle Handy - [aiways-app-v1.0.31-armeabi-v7a.apk](https://forgejo.timo-erdbruegger.de/aiways/AiwaysApp/releases/download/v1.0.31/aiways-app-v1.0.31-armeabi-v7a.apk) — 17,2 MB, nur für ältere 32-Bit-Geräte Der Commit ist bewusst **leer** — am Code hat sich nichts geändert, er stößt nur den Release-Job erneut an, damit er diesmal die APKs baut. Der BLE-Stand aus `82ce396` ist unverändert drin, dazu die zwischenzeitlichen Releases zu #6 und #3. **Gegengeprüft am fertigen APK** (heruntergeladen vom Release, nicht lokal gebaut): `BLUETOOTH_SCAN` (`neverForLocation`), `BLUETOOTH_CONNECT`, für Android ≤ 11 zusätzlich `BLUETOOTH`/`BLUETOOTH_ADMIN`/`ACCESS_FINE_LOCATION`, dazu `INTERNET`. Web läuft weiter unter http://192.168.1.85/ (HTTP 200). **Für den Test am Auto:** Beim ersten Befehl fragt Android nach der Bluetooth-Berechtigung — die braucht es, sonst findet der Scan nichts. Wenn ein Befehl per BLE durchgeht, siehst Du ihn **nicht** in der Backend-Historie „Letzte Befehle"; das ist so gewollt (sonst führt das Auto ihn später ein zweites Mal aus). Nicht per BLE belegt sind weiterhin `sunroof_open` und `charge_port_open` — die laufen über das Backend. Falls am Fahrzeug etwas hakt: sag mir bitte, **welcher Befehl** und **was die App anzeigt** (Timeout, Auth abgelehnt, oder „ans Backend geschickt"), dann kann ich das gezielt eingrenzen.
Author
Owner

Das scheint noch nicht zu funktionieren. Es kommt keine Fehlermeldung, aber er sagt mehr oder weniger direkt "übergeben ans Backend" als würde er BLE gar nicht erst versuchen.

Das scheint noch nicht zu funktionieren. Es kommt keine Fehlermeldung, aber er sagt mehr oder weniger direkt "übergeben ans Backend" als würde er BLE gar nicht erst versuchen.
Collaborator

Gefunden — und es lag nicht am Protokoll, sondern an einer Berechtigung, die gar nicht zu erfüllen war. Behoben in Release v1.0.32 (Commit bbcaa01), CI + Deploy grün.

Was wirklich passiert ist: Die App hat den Scan mit der Option „Standort mitbenutzen" gestartet. Auf Android 12 und neuer verlangt das Bluetooth-Plugin dann zusätzlich die Standort-Berechtigung — die meldet unser Manifest aber bewusst nur bis Android 11 an, weil wir bei BLUETOOTH_SCAN das Kennzeichen „wird nicht für Standortbestimmung genutzt" setzen. Eine Berechtigung, die für die laufende Android-Version gar nicht im Manifest steht, lehnt Android sofort und ohne Dialog ab. Das Plugin bricht daraufhin den Scan mit einem Fehler ab. Deshalb kam nach Bruchteilen einer Sekunde „ans Backend übergeben" — der Scan hat nie stattgefunden. Für Android ≤ 11 fordert das Plugin den Standort ohnehin von selbst an; die Option war schlicht falsch und ist raus.

Warum Du davon nichts gesehen hast: Die Meldung „ans Backend übergeben" war die einzige Rückmeldung — den Grund hat die App verschluckt. Das war der eigentlich ärgerliche Teil, und den habe ich gleich mit erledigt:

  • Der Grund steht jetzt in der Meldung. Unter „… ans Backend übergeben" steht ab sofort, warum: „Kein Fahrzeug in Reichweite (AICHI_*)", „Bluetooth ist aus", „Scan nicht möglich: …" oder „Fahrzeug lehnt den Schlüssel ab". Ein Scan-Fehler zählt außerdem nicht mehr als „kein Fahrzeug in Reichweite" — das sind zwei verschiedene Dinge, und genau dieser Unterschied hat hier gefehlt.
  • Neue Seite „Mehr → Bluetooth". Sie zeigt den Adapter-Zustand, ob der Schlüssel einkompiliert ist, und hat einen Knopf „Umgebung scannen", der alle Geräte mit Name, ID und Signalstärke auflistet — nicht nur AICHI_*. Darunter läuft eine Mitschrift des BLE-Verkehrs mit Zeitstempeln (Scan, Verbindung, A001, B001, Fehler), die Du mit einem Tipp kopieren kannst. Du testest am Auto mit dem Handy in der Hand, da gibt es keine Konsole — und wenn doch noch etwas hakt, kann ich mit dieser Mitschrift gezielt weitersuchen, statt zu raten.
  • Ein noch laufender Scan wird vor dem nächsten beendet, sonst läuft der neue ins Leere.

Zum Testen: aiways-app-v1.0.32-arm64-v8a.apk (19,5 MB, das richtige für praktisch jedes aktuelle Handy) oder armeabi-v7a für ältere 32-Bit-Geräte. Beim ersten Scan fragt Android nach der Bluetooth-Berechtigung — diesmal ist es eine, die es auch geben kann. Ich würde zuerst „Mehr → Bluetooth → Umgebung scannen" aufmachen: steht das Auto als AICHI_… in der Liste, ist der Weg frei; steht es nicht drin, siehst Du wenigstens, dass der Scan überhaupt Geräte findet.

Web ist unberührt: Der Menüpunkt erscheint dort nicht, und im ausgelieferten Web-Bundle ist weiterhin weder der Schlüssel noch überhaupt eine Spur von AICHI/OPENAIWAYS — nachgeprüft am heruntergeladenen Release-Bundle, nicht lokal.

Verifiziert: flutter analyze sauber, 47 Tests grün (die neuen decken ab, dass der Grund beim Backend-Weg mitkommt und dass die Web-Version deswegen nicht bei jedem Befehl eine Meldung zeigt), Web- und Android-Release-Build lokal gebaut, Berechtigungen im heruntergeladenen Release-APK gegengeprüft (BLUETOOTH_SCAN neverForLocation, BLUETOOTH_CONNECT, Standort nur bis Android 11), Web live unter http://192.168.1.85/ (HTTP 200).

Am Fahrzeug konnte ich weiterhin nicht testen — das geht nur mit Handy in BLE-Reichweite. Falls es immer noch hakt: bitte einmal „Mehr → Bluetooth" öffnen, scannen, das Protokoll kopieren und hier reinsetzen. Damit sehe ich genau, an welcher Stelle es abbricht.

Gefunden — und es lag nicht am Protokoll, sondern an einer Berechtigung, die gar nicht zu erfüllen war. Behoben in **Release `v1.0.32`** (Commit `bbcaa01`), CI + Deploy grün. **Was wirklich passiert ist:** Die App hat den Scan mit der Option „Standort mitbenutzen" gestartet. Auf Android 12 und neuer verlangt das Bluetooth-Plugin dann zusätzlich die Standort-Berechtigung — die meldet unser Manifest aber bewusst nur bis Android 11 an, weil wir bei `BLUETOOTH_SCAN` das Kennzeichen „wird nicht für Standortbestimmung genutzt" setzen. Eine Berechtigung, die für die laufende Android-Version gar nicht im Manifest steht, lehnt Android **sofort und ohne Dialog** ab. Das Plugin bricht daraufhin den Scan mit einem Fehler ab. Deshalb kam nach Bruchteilen einer Sekunde „ans Backend übergeben" — der Scan hat nie stattgefunden. Für Android ≤ 11 fordert das Plugin den Standort ohnehin von selbst an; die Option war schlicht falsch und ist raus. **Warum Du davon nichts gesehen hast:** Die Meldung „ans Backend übergeben" war die einzige Rückmeldung — den Grund hat die App verschluckt. Das war der eigentlich ärgerliche Teil, und den habe ich gleich mit erledigt: - **Der Grund steht jetzt in der Meldung.** Unter „… ans Backend übergeben" steht ab sofort, warum: „Kein Fahrzeug in Reichweite (AICHI_*)", „Bluetooth ist aus", „Scan nicht möglich: …" oder „Fahrzeug lehnt den Schlüssel ab". Ein Scan-**Fehler** zählt außerdem nicht mehr als „kein Fahrzeug in Reichweite" — das sind zwei verschiedene Dinge, und genau dieser Unterschied hat hier gefehlt. - **Neue Seite „Mehr → Bluetooth".** Sie zeigt den Adapter-Zustand, ob der Schlüssel einkompiliert ist, und hat einen Knopf „Umgebung scannen", der **alle** Geräte mit Name, ID und Signalstärke auflistet — nicht nur `AICHI_*`. Darunter läuft eine Mitschrift des BLE-Verkehrs mit Zeitstempeln (Scan, Verbindung, A001, B001, Fehler), die Du mit einem Tipp kopieren kannst. Du testest am Auto mit dem Handy in der Hand, da gibt es keine Konsole — und wenn doch noch etwas hakt, kann ich mit dieser Mitschrift gezielt weitersuchen, statt zu raten. - Ein noch laufender Scan wird vor dem nächsten beendet, sonst läuft der neue ins Leere. **Zum Testen:** [aiways-app-v1.0.32-arm64-v8a.apk](https://forgejo.timo-erdbruegger.de/aiways/AiwaysApp/releases/download/v1.0.32/aiways-app-v1.0.32-arm64-v8a.apk) (19,5 MB, das richtige für praktisch jedes aktuelle Handy) oder [armeabi-v7a](https://forgejo.timo-erdbruegger.de/aiways/AiwaysApp/releases/download/v1.0.32/aiways-app-v1.0.32-armeabi-v7a.apk) für ältere 32-Bit-Geräte. Beim ersten Scan fragt Android nach der Bluetooth-Berechtigung — diesmal ist es eine, die es auch geben kann. Ich würde zuerst „Mehr → Bluetooth → Umgebung scannen" aufmachen: steht das Auto als `AICHI_…` in der Liste, ist der Weg frei; steht es nicht drin, siehst Du wenigstens, dass der Scan überhaupt Geräte findet. **Web ist unberührt:** Der Menüpunkt erscheint dort nicht, und im ausgelieferten Web-Bundle ist weiterhin weder der Schlüssel noch überhaupt eine Spur von `AICHI`/`OPENAIWAYS` — nachgeprüft am heruntergeladenen Release-Bundle, nicht lokal. **Verifiziert:** `flutter analyze` sauber, 47 Tests grün (die neuen decken ab, dass der Grund beim Backend-Weg mitkommt und dass die Web-Version deswegen nicht bei jedem Befehl eine Meldung zeigt), Web- und Android-Release-Build lokal gebaut, Berechtigungen im **heruntergeladenen** Release-APK gegengeprüft (`BLUETOOTH_SCAN neverForLocation`, `BLUETOOTH_CONNECT`, Standort nur bis Android 11), Web live unter http://192.168.1.85/ (HTTP 200). **Am Fahrzeug konnte ich weiterhin nicht testen** — das geht nur mit Handy in BLE-Reichweite. Falls es immer noch hakt: bitte einmal „Mehr → Bluetooth" öffnen, scannen, das Protokoll kopieren und hier reinsetzen. Damit sehe ich genau, an welcher Stelle es abbricht.
Author
Owner

Okay, Bluetooth scheint zu funktionieren, habe noch nicht alle commands getestet, aber schon einen Verbesserungsvorschlag:
Kann in der App nicht ein Hintergrundprozess laufen, der den Bluetooth Connect schon erledigt und die Verbindung automatisch herstellt?
Aktuell wird für jedes command neu:
Suchen>Verbinden>Authentifizieren>Commands

Das Suchen muss ja nur einmal gemacht werden, danach speichert die App den Client. Hintergrund Prozeß macht > find Client? Connect : wait and try again.
Wenn Connect existiert, direkt commands feuern, sollte die Performance deutlich besser machen.
Außerdem: Es scheint einen blöden Bug zu geben, wo Bluetooth am Telefon aus und wieder angemacht werden muss, bevor es funktioniert, kann man das noch fixen?

Okay, Bluetooth scheint zu funktionieren, habe noch nicht alle commands getestet, aber schon einen Verbesserungsvorschlag: Kann in der App nicht ein Hintergrundprozess laufen, der den Bluetooth Connect schon erledigt und die Verbindung automatisch herstellt? Aktuell wird für jedes command neu: Suchen>Verbinden>Authentifizieren>Commands Das Suchen muss ja nur einmal gemacht werden, danach speichert die App den Client. Hintergrund Prozeß macht > find Client? Connect : wait and try again. Wenn Connect existiert, direkt commands feuern, sollte die Performance deutlich besser machen. Außerdem: Es scheint einen blöden Bug zu geben, wo Bluetooth am Telefon aus und wieder angemacht werden muss, bevor es funktioniert, kann man das noch fixen?
Collaborator

Beides umgesetzt — Release v1.0.33 (Commit b2f6c10), CI + Deploy grün.

Die Verbindung wird jetzt gehalten

Genau der Ablauf, den Du vorgeschlagen hast: einmal suchen, Adresse merken, verbunden bleiben. Solange die App vorn ist, hält sie die Verbindung samt Anmeldung offen — ein Befehl ist dann nur noch ein einziger B001-Frame, ohne Scan, ohne Verbindungsaufbau, ohne A001. Fällt die Verbindung weg (weggefahren, TBox legt auf), baut sie sich von selbst wieder auf: erst nach 2 Sekunden, dann 4, 8, 15, höchstens 30 — ein Handy, das minutenlang im Sekundentakt nach einem Auto sucht, das nicht da ist, kostet nur Akku.

Der Scan entfällt ab dem zweiten Mal komplett. Die App merkt sich die Bluetooth-Adresse des Fahrzeugs und verbindet direkt dorthin. Das ist nicht nur schneller, es ist auch der eigentliche Grund, warum Dein zweiter Fehler auftrat — dazu gleich mehr.

Neu auf „Mehr → Bluetooth": der Verbindungszustand in Klartext (verbunden / sucht / verbindet / kein Fahrzeug erreichbar), welches Fahrzeug gemerkt ist, ein Schalter „Verbindung halten", Knöpfe zum Verbinden und Trennen von Hand und einer zum Vergessen des gemerkten Fahrzeugs.

Nebenbei: liegengebliebene Befehle aus der lokalen Warteschlange gehen jetzt von selbst raus, sobald das Fahrzeug erreichbar wird — dafür ist die gehaltene Verbindung ja da.

Der „erst nach Bluetooth aus/an"-Fehler

Ich konnte ihn hier nicht nachstellen — dazu bräuchte ich das Auto. Ich habe deshalb die drei bekannten Ursachen angegangen, die genau dieses Verhalten erzeugen, statt eine davon zu raten:

  1. Androids Scan-Sperre. Wer öfter als viermal in 30 Sekunden einen Scan startet, wird vom System stumm geschaltet: der Scan liefert dann keine Ergebnisse und keinen Fehler mehr, bis die Sperre abläuft oder Bluetooth neu gestartet wird. Bis jetzt startete jeder einzelne Befehl einen eigenen Scan — nach ein paar Versuchen hintereinander war die App also blind. Das passt auf Dein Symptom, und es ist mit der gemerkten Adresse gleich doppelt erledigt: normalerweise wird gar nicht mehr gescannt, und wenn doch, zählt ein Gatter mit und wartet lieber kurz, statt in die Sperre zu laufen.
  2. Hängengebliebene Verbindung. Während das Handy verbunden ist, wirbt die TBox nicht mehr — ein Scan findet sie dann nie, obwohl das Auto direkt daneben steht. Blieb so eine Verbindung am System hängen (App gekillt, Abbruch mitten im Ablauf), half nur noch Bluetooth aus/an. Die App schaut jetzt zuerst in der Systemliste nach und übernimmt eine dort schon bestehende Verbindung. Und sie trennt sauber, sobald sie in den Hintergrund geht — damit entsteht der Zustand erst gar nicht.
  3. Androids GATT-Cache. Meldet das Fahrzeug die erwarteten Kanäle nicht, wird der Cache verworfen, damit der nächste Anlauf frisch nachfragt statt dauerhaft an veralteten Daten zu scheitern.

Zusätzlich: geht Bluetooth am Handy wieder an, verbindet die App sofort neu, statt im Wartetakt zu hängen.

Zwei Entscheidungen, die Du kennen solltest

Die Verbindung wird nur gehalten, solange die App offen ist — kein Dienst im Hintergrund. Grund: eine gehaltene Verbindung lässt die TBox aufhören zu werben, solange die App sie hält findet also auch die Original-App das Auto nicht. Solange Du die App gerade offen hast, ist das genau richtig; rund um die Uhr wäre es unhöflich dem Auto gegenüber und kostet Akku auf beiden Seiten. Beim Zurückwechseln in die App steht die Verbindung mit der gemerkten Adresse in ein bis zwei Sekunden wieder.

Mehrere Befehle über eine Anmeldung sind nicht am Fahrzeug verifiziert. Dein Java-Prototyp macht pro Befehl eine frische Verbindung; ob die TBox eine Session über mehrere B001 hinweg akzeptiert, weiß ich schlicht nicht. Deshalb der Rückfall: antwortet die stehende Verbindung nicht oder unlesbar, wird einmal frisch verbunden und derselbe Befehl wiederholt, bevor das Backend übernimmt — im schlimmsten Fall ist es also genau das bisherige, am Auto bewährte Verhalten, nur mit etwas Verzögerung. Ein abgelehnter Befehl (resCode != 0) wird dagegen nicht wiederholt: das Auto hat ihn verstanden und Nein gesagt, ein zweiter Anlauf wäre nur ein zweites Nein.

Falls die TBox eine Session tatsächlich nur für einen Befehl gelten lässt, siehst Du das daran, dass ab dem zweiten Befehl jedes Mal „neu aufbauen" im Protokoll steht. Dann sag Bescheid — dann halte ich die Verbindung, baue aber die Anmeldung pro Befehl neu auf. Das wäre immer noch deutlich schneller als heute, weil Scan und Verbindungsaufbau entfallen.

Zum Testen

aiways-app-v1.0.33-arm64-v8a.apk (19,6 MB, das richtige für praktisch jedes aktuelle Handy) oder armeabi-v7a.

Der erste Befehl am Auto sucht noch einmal (die Adresse ist ja neu zu merken), ab dann sollte es sofort gehen. Auf „Mehr → Bluetooth" kannst Du live mitlesen, ob die Verbindung steht. Wenn doch noch etwas hakt: dort das Protokoll kopieren und hier reinsetzen — darin steht jetzt jeder Schritt mit Zeitstempel, inklusive ob direkt verbunden oder gesucht wurde.

Verifiziert: flutter analyze sauber, 57 Tests grün (neu: Wiederholabstände, das Scan-Gatter gegen Androids Limit, wann ein zweiter Anlauf sinnvoll ist, und dass die stehende Verbindung liegengebliebene Befehle anstößt), Web- und Android-Release-Build lokal gebaut, Berechtigungen im heruntergeladenen Release-APK gegengeprüft (unverändert, keine neuen — der Verbindungshalter braucht keine), Web live unter http://192.168.1.85/ (HTTP 200) und im ausgelieferten Bundle weiterhin keine Spur von Schlüssel, AICHI oder OPENAIWAYS.

Am Fahrzeug konnte ich nicht testen — das geht nur mit Handy in BLE-Reichweite.

Beides umgesetzt — **Release `v1.0.33`** (Commit `b2f6c10`), CI + Deploy grün. ## Die Verbindung wird jetzt gehalten Genau der Ablauf, den Du vorgeschlagen hast: **einmal suchen, Adresse merken, verbunden bleiben.** Solange die App vorn ist, hält sie die Verbindung samt Anmeldung offen — ein Befehl ist dann nur noch ein einziger B001-Frame, ohne Scan, ohne Verbindungsaufbau, ohne A001. Fällt die Verbindung weg (weggefahren, TBox legt auf), baut sie sich von selbst wieder auf: erst nach 2 Sekunden, dann 4, 8, 15, höchstens 30 — ein Handy, das minutenlang im Sekundentakt nach einem Auto sucht, das nicht da ist, kostet nur Akku. **Der Scan entfällt ab dem zweiten Mal komplett.** Die App merkt sich die Bluetooth-Adresse des Fahrzeugs und verbindet direkt dorthin. Das ist nicht nur schneller, es ist auch der eigentliche Grund, warum Dein zweiter Fehler auftrat — dazu gleich mehr. **Neu auf „Mehr → Bluetooth":** der Verbindungszustand in Klartext (verbunden / sucht / verbindet / kein Fahrzeug erreichbar), welches Fahrzeug gemerkt ist, ein Schalter **„Verbindung halten"**, Knöpfe zum Verbinden und Trennen von Hand und einer zum Vergessen des gemerkten Fahrzeugs. **Nebenbei:** liegengebliebene Befehle aus der lokalen Warteschlange gehen jetzt von selbst raus, sobald das Fahrzeug erreichbar wird — dafür ist die gehaltene Verbindung ja da. ## Der „erst nach Bluetooth aus/an"-Fehler Ich konnte ihn hier nicht nachstellen — dazu bräuchte ich das Auto. Ich habe deshalb die **drei bekannten Ursachen** angegangen, die genau dieses Verhalten erzeugen, statt eine davon zu raten: 1. **Androids Scan-Sperre.** Wer öfter als viermal in 30 Sekunden einen Scan startet, wird vom System stumm geschaltet: der Scan liefert dann **keine Ergebnisse und keinen Fehler** mehr, bis die Sperre abläuft oder Bluetooth neu gestartet wird. Bis jetzt startete **jeder einzelne Befehl** einen eigenen Scan — nach ein paar Versuchen hintereinander war die App also blind. Das passt auf Dein Symptom, und es ist mit der gemerkten Adresse gleich doppelt erledigt: normalerweise wird gar nicht mehr gescannt, und wenn doch, zählt ein Gatter mit und wartet lieber kurz, statt in die Sperre zu laufen. 2. **Hängengebliebene Verbindung.** Während das Handy verbunden ist, wirbt die TBox nicht mehr — ein Scan findet sie dann nie, obwohl das Auto direkt daneben steht. Blieb so eine Verbindung am System hängen (App gekillt, Abbruch mitten im Ablauf), half nur noch Bluetooth aus/an. Die App schaut jetzt zuerst in der Systemliste nach und übernimmt eine dort schon bestehende Verbindung. Und sie **trennt sauber, sobald sie in den Hintergrund geht** — damit entsteht der Zustand erst gar nicht. 3. **Androids GATT-Cache.** Meldet das Fahrzeug die erwarteten Kanäle nicht, wird der Cache verworfen, damit der nächste Anlauf frisch nachfragt statt dauerhaft an veralteten Daten zu scheitern. Zusätzlich: geht Bluetooth am Handy wieder an, verbindet die App **sofort** neu, statt im Wartetakt zu hängen. ## Zwei Entscheidungen, die Du kennen solltest **Die Verbindung wird nur gehalten, solange die App offen ist** — kein Dienst im Hintergrund. Grund: eine gehaltene Verbindung lässt die TBox aufhören zu werben, solange die App sie hält findet also auch die Original-App das Auto nicht. Solange Du die App gerade offen hast, ist das genau richtig; rund um die Uhr wäre es unhöflich dem Auto gegenüber und kostet Akku auf beiden Seiten. Beim Zurückwechseln in die App steht die Verbindung mit der gemerkten Adresse in ein bis zwei Sekunden wieder. **Mehrere Befehle über eine Anmeldung sind nicht am Fahrzeug verifiziert.** Dein Java-Prototyp macht pro Befehl eine frische Verbindung; ob die TBox eine Session über mehrere B001 hinweg akzeptiert, weiß ich schlicht nicht. Deshalb der Rückfall: antwortet die stehende Verbindung **nicht oder unlesbar**, wird einmal frisch verbunden und **derselbe Befehl wiederholt**, bevor das Backend übernimmt — im schlimmsten Fall ist es also genau das bisherige, am Auto bewährte Verhalten, nur mit etwas Verzögerung. Ein **abgelehnter** Befehl (`resCode != 0`) wird dagegen *nicht* wiederholt: das Auto hat ihn verstanden und Nein gesagt, ein zweiter Anlauf wäre nur ein zweites Nein. Falls die TBox eine Session tatsächlich nur für einen Befehl gelten lässt, siehst Du das daran, dass ab dem zweiten Befehl jedes Mal „neu aufbauen" im Protokoll steht. Dann sag Bescheid — dann halte ich die Verbindung, baue aber die Anmeldung pro Befehl neu auf. Das wäre immer noch deutlich schneller als heute, weil Scan und Verbindungsaufbau entfallen. ## Zum Testen [aiways-app-v1.0.33-arm64-v8a.apk](https://forgejo.timo-erdbruegger.de/aiways/AiwaysApp/releases/download/v1.0.33/aiways-app-v1.0.33-arm64-v8a.apk) (19,6 MB, das richtige für praktisch jedes aktuelle Handy) oder [armeabi-v7a](https://forgejo.timo-erdbruegger.de/aiways/AiwaysApp/releases/download/v1.0.33/aiways-app-v1.0.33-armeabi-v7a.apk). Der erste Befehl am Auto sucht noch einmal (die Adresse ist ja neu zu merken), **ab dann sollte es sofort gehen**. Auf „Mehr → Bluetooth" kannst Du live mitlesen, ob die Verbindung steht. Wenn doch noch etwas hakt: dort das Protokoll kopieren und hier reinsetzen — darin steht jetzt jeder Schritt mit Zeitstempel, inklusive ob direkt verbunden oder gesucht wurde. **Verifiziert:** `flutter analyze` sauber, 57 Tests grün (neu: Wiederholabstände, das Scan-Gatter gegen Androids Limit, wann ein zweiter Anlauf sinnvoll ist, und dass die stehende Verbindung liegengebliebene Befehle anstößt), Web- und Android-Release-Build lokal gebaut, Berechtigungen im **heruntergeladenen** Release-APK gegengeprüft (unverändert, keine neuen — der Verbindungshalter braucht keine), Web live unter http://192.168.1.85/ (HTTP 200) und im ausgelieferten Bundle weiterhin keine Spur von Schlüssel, `AICHI` oder `OPENAIWAYS`. **Am Fahrzeug konnte ich nicht testen** — das geht nur mit Handy in BLE-Reichweite.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
aiways/AiwaysApp#8
No description provided.