Status: updated in CarDash 1.2.9; OBD hardware still needs a real-car test. Last updated: 2026-11-02
CarDash optionally reads live data from a Bluetooth Classic ELM327 adapter in the car's OBD-II port and shows it on the home page. Settings has separate OBD-II, Speed and Temperature cards. Speed can be hidden, sourced from OBD-II or GPS, and temperature can be hidden, sourced from OBD-II ambient or GPS + the Open-Meteo weather provider.
| Value | PID | Notes |
|---|---|---|
| Vehicle speed, km/h | 0D |
Digital home readout |
| Throttle, % | 49, fallback 11 |
Horizontal bar |
| Engine fuel rate, L/h | 5E |
Preferred fuel-economy input |
| MAF, g/s | 10 |
Fuel-economy fallback input |
| Ambient temperature, °C | 46 |
OBD temperature row |
The economy figure is a 5 km rolling average in L/100 km. It prefers the
ECU's engine-fuel-rate PID (5E), which follows the same injection data as the
car's trip computer and works for petrol and diesel. If the vehicle does not
report 5E, it falls back to MAF with petrol constants (stoichiometric AFR
14.7, 745 g/L), ignores MAF on a closed-throttle coast above 10 km/h, and shows
— until at least 0.5 km has accumulated. The MAF fallback is an estimate and
is not suitable for a diesel engine; such a vehicle needs PID 5E for an
accurate figure.
04/08 writes; CarDash is read-only.| # | Decision |
|---|---|
| D1 | Bluetooth Classic SPP only; only devices already paired in Android Settings. No scan UI. |
| D2 | Throttle uses accelerator 49, falling back to plate 11. |
| D3 | Metric L/100 km only. |
| D4 | Small live speed card above the volume card; temperature row below the date. |
| D5 | Rolling window resets on disconnect or a sample gap over 30 s. |
| D6 | No fuel level or range. |
| D7 | OBD ambient wins over weather while the OBD temperature source is selected. |
| D8 | Speed and temperature each have an independent show/hide switch in Settings. |
| D9 | Source switches appear only while an OBD-II adapter is selected; GPS/weather is the fallback. |
| D10 | Temperature starts off on fresh installs; upgrades that already used OBD or weather keep it on. |
| D11 | The picker defaults to devices that look like Bluetooth Classic OBD-II adapters; Show all paired devices is the explicit escape hatch. |
| D12 | Every Bluetooth binder call runs on one serialized native worker, never on the MethodChannel/main thread. |
| D13 | Connection attempts stop after three failures; the card offers Retry connection. There is no infinite reconnect loop. |
| Feature | Manifest | Runtime |
|---|---|---|
| Bluetooth 29–30 | BLUETOOTH, BLUETOOTH_ADMIN (maxSdkVersion="30") |
install-time |
| Bluetooth 31+ | BLUETOOTH_CONNECT |
requested from the OBD-II card |
| Weather | INTERNET, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION |
location requested when temperature/weather is enabled |
There is no BLUETOOTH_SCAN. The app lists bonded devices only and requests
Bluetooth permission from the OBD-II card before listing them.
Location is one-shot. Coordinates and place names are held only in memory for
the current weather value; they are not persisted. The adapter address, speed
and temperature visibility, source choices and weather preference are persisted
in SettingsRepository.
Kotlin
TelemetryBridge MethodChannel "com.wasp.cardash_launcher/telemetry"
- bluetoothState / listBondedDevices / ensureBluetoothPermission
- connectObd(mac) / disconnectObd / getObdState
- ensureLocationPermission / getLocation (last-known or single fix + Geocoder)
- all Bluetooth binder work runs on the cardash-bluetooth worker
ObdService one worker thread over BluetoothSocket/RFCOMM SPP
- handshake ATZ, ATE0, ATL0, ATS0, ATSP0
- request/response serialized, prompt-terminated
- 12 s connect watchdog, three attempts, then retryExhausted
Dart
NativeTelemetryBridge platform boundary
ObdController connection lifecycle, 1 s snapshot polling, status
ObdEconomy fuel-rate or MAF/speed integrator with 5 km window
TelemetrySettingsController
persisted speed/temperature visibility and source
WeatherController permission, one-shot location, 15 min weather cache
WeatherService keyless Open-Meteo current temperature_2m
TelemetryBridge models BluetoothDeviceInfo / LocationReading / ObdState
SettingsRepository adapter address, speed/temperature flags, weather
The native ObdService warms the adapter with a 0100 request after ATSP0,
drops any stale input before each command and probes 5E in the poll loop,
retrying every 30 cycles while it is unsupported. It polls speed, fuel rate,
MAF and throttle roughly once per second; ambient temperature is refreshed
every 30 poll cycles. A snapshot carries
updatedAt; the Dart side treats data older than five seconds as stale and
hides the live card. Connection failures surface as a short Settings status and
keep the dashboard quiet. A failure after three attempts sets retryExhausted;
the card then shows Retry connection and the controller does not auto-retry
on the next resume.
Outside, 7°CSofia, 7°C (or Current location, 7°C)Speed card in the left column above the media-volume card, only while the Speed switch is on and a fresh source value exists:
● OBD-II LIVE
44 km/h
Throttle 22%
[========------------------]
Rolling economy 7.5 L/100 km
When the GPS source is selected (or OBD is unavailable), the card reads
GPS / FROM LOCATION with the GPS speed instead.
OBD-II
None and paired Bluetooth Classic devices that
look like OBD-II adapters (known name, SPP UUID, or a plausible major class).
Show all paired devices reveals phones, headsets and other bonded devices.Find/Allow requests Bluetooth permission and refreshes the list.Speed
Temperature
Selecting a device persists its MAC address and connects immediately when the
app is active. Selecting None disconnects. Polling stops when CarDash leaves
the foreground and reconnects on resume.
WeatherController:
TelemetryBridge.getLocation.Geocoder.https://api.open-meteo.com/v1/forecast?...¤t=temperature_2m&timezone=auto
Any failure clears the temperature and hides the row. No API key, account or coordinates are stored.
-40/215 sentinel values are rejected.Ukiah, 17°C during implementation).5E (engine fuel rate):
it matches the car's trip computer and is the only reliable MAF-free source
for a diesel engine. MAF/AFR remains the petrol-only fallback.—: the one-shot supported-PID query before the poll could race the ATSP0
protocol search and shift every later response by one command. The warm-up
request, stale-input drain and in-loop 5E probe keep the ELM327 stream
aligned and make an unsupported 5E cost at most one probe per 30 cycles.