Compare commits

...

4 Commits

Author SHA1 Message Date
bonzi 972deb93df Clarify Raspberry Pi low voltage warning 2026-08-01 11:17:16 +00:00
bonzi 518ee028a3 Add first test drive notes 2026-08-01 05:31:49 +00:00
alex 15d13cc52f Recover Android BLE connection after Pi restart 2026-08-01 01:08:55 +02:00
alex d2934690a5 Fix BLE advertising after reboot 2026-08-01 01:08:48 +02:00
4 changed files with 316 additions and 8 deletions
@@ -12,6 +12,7 @@ import android.os.ParcelUuid
import android.os.Handler
import android.os.Looper
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withTimeout
import org.json.JSONObject
@@ -36,19 +37,35 @@ class BleClient(private val context: Context) {
private val writes = ArrayDeque<ByteArray>()
private var writeInProgress = false
private val handler = Handler(Looper.getMainLooper())
private val reconnect: Runnable = Runnable { connect() }
private val restartScan: Runnable = Runnable {
if (!stopped && state.value == ConnectionState.SCANNING) {
bluetoothManager.adapter?.bluetoothLeScanner?.stopScan(scanCallback)
scheduleReconnect(1_000)
}
}
private var stopped = true
fun connect() {
stopped = false
val adapter = bluetoothManager.adapter ?: return
handler.removeCallbacks(reconnect)
handler.removeCallbacks(restartScan)
val adapter = bluetoothManager.adapter ?: run {
state.value = ConnectionState.DISCONNECTED
scheduleReconnect()
return
}
adapter.bluetoothLeScanner?.stopScan(scanCallback)
state.value = ConnectionState.SCANNING
val filter = ScanFilter.Builder().setServiceUuid(ParcelUuid(SERVICE_UUID)).build()
adapter.bluetoothLeScanner?.startScan(listOf(filter), ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(), scanCallback)
handler.postDelayed(restartScan, 15_000)
}
fun disconnect() {
stopped = true
handler.removeCallbacksAndMessages(null)
handler.removeCallbacks(reconnect)
handler.removeCallbacks(restartScan)
bluetoothManager.adapter?.bluetoothLeScanner?.stopScan(scanCallback)
gatt?.close(); gatt = null; rx = null
resetWrites()
@@ -64,21 +81,30 @@ class BleClient(private val context: Context) {
enqueue((message.toString() + "\n").toByteArray())
return try {
withTimeout(20_000) { deferred.await() }
} catch (error: TimeoutCancellationException) {
handler.post { gatt?.disconnect() }
throw error
} finally {
pending.remove(id)
}
}
private val scanCallback = object : ScanCallback() {
private val scanCallback: ScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
handler.removeCallbacks(restartScan)
bluetoothManager.adapter.bluetoothLeScanner?.stopScan(this)
state.value = ConnectionState.CONNECTING
gatt?.close()
gatt = result.device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
}
override fun onScanFailed(errorCode: Int) { state.value = ConnectionState.DISCONNECTED }
override fun onScanFailed(errorCode: Int) {
handler.removeCallbacks(restartScan)
state.value = ConnectionState.DISCONNECTED
scheduleReconnect()
}
}
private val gattCallback = object : BluetoothGattCallback() {
private val gattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
this@BleClient.gatt = gatt
@@ -88,8 +114,10 @@ class BleClient(private val context: Context) {
if (!gatt.requestMtu(247)) gatt.discoverServices()
}
else {
rx = null; gatt.close(); resetWrites(); state.value = ConnectionState.DISCONNECTED
if (!stopped) handler.postDelayed({ connect() }, 3_000)
rx = null; gatt.close()
if (this@BleClient.gatt === gatt) this@BleClient.gatt = null
resetWrites(); state.value = ConnectionState.DISCONNECTED
scheduleReconnect()
}
}
@@ -195,4 +223,10 @@ class BleClient(private val context: Context) {
writes.clear()
writeInProgress = false
}
private fun scheduleReconnect(delayMillis: Long = 3_000) {
if (stopped) return
handler.removeCallbacks(reconnect)
handler.postDelayed(reconnect, delayMillis)
}
}
Binary file not shown.
+274
View File
@@ -0,0 +1,274 @@
---
title: Pi Car Companion - First Test Drive
aliases:
- First Test Drive Notes
project: Pi Car Companion
type: field-notes
status: Follow-up required
date: Unknown
source: https://git.molberg.cloud/alex/pi-car-companion
tags:
- pi-car-companion
- mg4
- first-test-drive
- telemetry
- android
- networking
---
# Pi Car Companion: First Test Drive
> [!info] Purpose
> Notes from the first real-world test drive of Pi Car Companion. This document is a pickup point for later project work. It records observations and questions, not an instruction to implement every item immediately.
## Scope and handling
> [!important] Do not over-implement
> The larger investigations and feature requests below must not be started automatically. They are notes for later pickup.
>
> Small, explicit, low-risk fixes for a specific listed problem may be made without separate approval. The inverted wheel animation in the web UI is an example of this kind of fix.
>
> Power, networking, ADB reliability, telemetry accuracy, Android Auto, battery-service access, new phone-app features, shell access, power controls, and map-provider changes require separate investigation and approval before implementation.
## Quick overview
| Area | Observation | Status |
|---|---|---|
| Power | Raspberry Pi desktop showed a low-voltage warning while powered by the power bank | Investigate later |
| ADB | Connection dropped during the drive | Investigate later |
| Speed | Readings were a few km/h low | Investigate later |
| Peak speed | Trip report missed the observed top speed | Investigate later |
| Wi-Fi | Hotspot disconnected repeatedly | Investigate later |
| Phone GPS | GPS should stop when the Pi is unreachable | Feature request |
| Phone app | More controls and trip features requested | Feature request |
| Trip map | OpenStreetMap `Referer` handling or another map solution needed | Investigate later |
| Android Auto | Repeated disconnects and unstable connection | Investigate later |
| Battery | Battery data could not be read | Investigate later |
| Web UI | Wheel animation direction is inverted | **Simple fix candidate** |
| Phone app | Wheel animation requested | Feature request |
## Detailed notes
### Raspberry Pi low-voltage warning while using the power bank
- The Raspberry Pi showed a desktop-environment notification saying: **"Low voltage. Please check power supply."**
- This happened while the Pi was running from the power bank.
- The power bank itself did not report the warning.
- Possible relation to the Pi, the AWUS1900, Wi-Fi instability, or other USB hardware is unknown.
**Follow-up question:** Is the power bank providing stable and sufficient power to the Raspberry Pi under load?
### ADB connection drops
- The ADB connection dropped during the test drive.
- The problem was visible in the phone app and in the trip GPS data.
**Follow-up questions:**
- Was the ADB connection drop caused by power, Wi-Fi, USB, or the infotainment system?
- How does the dropout affect trip recording and phone-app state?
### Speed and peak-speed data
- Speed was a few km/h off:
- Approximately `65 km/h` in reality.
- Approximately `63-64 km/h` reported.
- Peak speed may not be logged quickly enough:
- Real top speed: `126 km/h`.
- Trip report: `116 km/h`.
- Phone app: `124 km/h`.
**Follow-up questions:**
- Is the difference caused by sampling interval, timestamp alignment, GPS smoothing, or trip aggregation?
- Why was the phone-app value closer to the observed top speed than the trip report?
### Wi-Fi hotspot instability
- The Wi-Fi hotspot disconnected constantly.
- A power-supply problem is suspected as one possible cause.
- The AWUS1900 may be rebooting because of insufficient power.
**Follow-up questions:**
- Does the AWUS1900 reset when the Raspberry Pi reports low voltage while powered by the power bank?
- Do Wi-Fi disconnects occur at the same time as ADB and Android Auto disconnects?
- Is the built-in Pi Wi-Fi adapter still stable when the AWUS1900 drops?
### Phone-app behavior when the Pi is unreachable
The phone app should eventually be able to:
- Stop sending GPS data when there is no connection to the Pi.
- Hide its notification while disconnected.
- Enter a low-power sleep state until the Pi connection returns.
- Resume GPS updates and the notification after reconnecting.
> [!note] Scope
> This is a behavior change in the Android companion, not a simple documentation or UI correction. Leave it as a later feature unless explicitly picked up.
### Additional phone-app features requested
- Edit shortcut apps.
- Possibly provide shell access.
- Reboot or power off the Pi.
- View trip data.
- Add a Settings page containing:
- Hotspot settings.
- Software update controls.
> [!warning] Safety and scope
> Shell access, reboot, and power-off are operational features with security and safety implications. Do not implement them from this note alone. Any future implementation must preserve the project's restricted, authenticated design.
### Trip-report map
- The trip-report map needs a `Referer` header for OpenStreetMap requests.
- Consider an alternative map provider.
- Consider whether map data could be pre-baked into the Android app and web UI.
**Follow-up questions:**
- Can the existing map integration send the required header correctly?
- Would an alternative provider or offline map data better fit the local-first design?
- What attribution and licensing requirements would apply?
### Android Auto disconnects
- Android Auto repeatedly disconnected.
- The connection was unstable.
Possible causes mentioned during the test:
- ADB instability.
- Wi-Fi interference.
- Bluetooth interference.
- Power instability.
No cause has been confirmed.
### Battery telemetry unavailable
- Battery data could not be read during the test.
The cause is unknown. The UI should continue to show battery values as unavailable rather than substituting unrelated Android head-unit battery data.
### Wheel animation
- The wheel animation is inverted in the web UI.
- The phone app should also receive a wheel animation.
> [!tip] Simple fix candidate
> Correcting the direction of the existing web UI wheel animation is an explicitly listed, small UI fix and may be handled independently. Adding a new wheel animation to the phone app is a separate feature and should not be assumed to be included in that permission.
## Later pickup checklist
### Reliability investigation
- [ ] Investigate the low-voltage warning from the power bank.
- [ ] Determine whether the AWUS1900 is rebooting or losing power.
- [ ] Investigate ADB connection drops.
- [ ] Investigate repeated Wi-Fi hotspot disconnects.
- [ ] Investigate Android Auto disconnects and possible Wi-Fi/Bluetooth interference.
### Telemetry investigation
- [ ] Review the small speed discrepancy.
- [ ] Review peak-speed sampling and trip aggregation.
- [ ] Investigate why battery data cannot be read.
### Phone-app feature work
- [ ] Design disconnected GPS behavior.
- [ ] Consider shortcut editing.
- [ ] Consider trip data support.
- [ ] Consider a phone-app Settings page.
- [ ] Evaluate whether shell, reboot, and power-off controls are appropriate.
- [ ] Consider adding wheel animation to the phone app.
### Map work
- [ ] Decide between fixing the OpenStreetMap request headers, using another provider, or supporting offline/pre-baked map data.
### Explicitly allowed simple fix
- [ ] Correct the inverted wheel animation in the web UI.
## English rewrite
- **Raspberry Pi:** The desktop environment showed a low-voltage warning saying, **"Low voltage. Please check power supply."** while the Pi was running from the power bank.
- **ADB connection dropped.**
- This was visible in the phone app and in the trip GPS data.
- **Speed was a few km/h off.**
- Approximately `65 km/h` was shown as `63-64 km/h`.
- **Peak speed may not be logged quickly enough.**
- Real top speed: `126 km/h`.
- Trip report: `116 km/h`.
- Phone app: `124 km/h`.
- **The Wi-Fi hotspot disconnected constantly.**
- Could this be a power-supply problem?
- Could the AWUS1900 be rebooting because of insufficient power?
- **The phone app should stop sending GPS data when it has no connection to the Pi.**
- Hide the notification and enter a low-power sleep state until the Pi connection returns.
- **The phone app needs more features.**
- Edit shortcut apps.
- Shell access?
- Reboot or power off the Pi.
- Trip data.
- Settings page:
- Hotspot settings.
- Software updates.
- **The trip-report map needs a `Referer` header for OpenStreetMap.**
- Alternative map provider?
- Could map data be pre-baked into the Android app and web UI?
- **Android Auto repeatedly disconnected and had an unstable connection.**
- Was it caused by ADB?
- Wi-Fi/Bluetooth interference?
- **Battery data could not be read.**
- **The wheel animation is inverted in the web UI.**
- Add wheel animation to the phone app.
## Original notes in Danish
- Raspberry Pi desktop environment showed a low-voltage warning ("Low voltage. Please check power supply") while running through the power bank
- ADB connection dropper ud
- Ses på telefon app, og trip GPS data
- Speed er få km/h off (65 -> 63-64 km/h)
- Peak speed logges ikke hurtigt nok?
- Ramte real 126 km/h top speed (trip siger 116 km/h)
- Telefon app viste 124 km/h
- WiFi hotspot disconnecter konstant.
- Power supply problem?
- Måske fordi AWUS 1900 rebooter pga lav strøm?
- Telefon app skal kunne stoppe med gps data når ingen forbindelse til pi
- skjul notifikation og gå i dvale indtil reconnect med pi
- Telefon app skal have flere features
- edit shortcut apps
- shell?
- Reboot/power off pi
- Trip data
- Settings page
- Hotspot settings
- Software Update
- Trip report map skal have Referer header til openstreetmap.
- Alternativ kort?
- Prebaked ind i App og web ui?
- Android Auto blev ved med at disconnect og havde sporty connection
- Skyldes ADB?
- WiFi/Bluetooth interference?
- Battery data kan ikke læses
- Wheel animation er inverted på web ui
- Tilføj wheel animation på telefon app
## Related project
- [[Pi Car Companion]]
- Repository: [alex/pi-car-companion](https://git.molberg.cloud/alex/pi-car-companion)
## Changelog
- Added as a project note under `notes/`.
- Preserved the original Danish notes.
- Added a structured English rewrite.
- Marked broad work as later pickup and separated the simple web wheel-animation fix.
> [!note] No implementation was made from this note.
+1 -1
View File
@@ -7,7 +7,7 @@ Wants=pi-car-companion.service
[Service]
Type=simple
ExecStart=/usr/local/libexec/pi-car-companion-bluetooth
ExecStartPost=-/usr/bin/timeout 10 /usr/bin/btmgmt add-adv -c -u 6c7a0001-7c6d-4f74-9bb0-c5a4e5efc001 1
ExecStartPost=/usr/bin/timeout 5 /usr/bin/script -qec '/usr/bin/btmgmt add-adv -c -u 6c7a0001-7c6d-4f74-9bb0-c5a4e5efc001 1' /dev/null
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true