OBD_TEMPERATURE.md 6.9 KB

CarDash — OBD-II and temperature design note

Status: implemented in CarDash 0.6.0; OBD hardware still needs a real-car test. Last updated: 2026-10-29

1. Scope

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. When OBD does not provide an ambient temperature, an optional location-based weather fallback can fill the temperature row.

Implemented values

Value PID Notes
Vehicle speed, km/h 0D Digital home readout
Throttle, % 49, fallback 11 Horizontal bar
MAF, g/s 10 Rolling fuel-economy input
Ambient temperature, °C 46 OBD temperature row

The economy figure is a 5 km rolling average in L/100 km. It uses 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.

Out of scope

  • RPM, coolant, module voltage, MIL/DTC contents, fuel level, range.
  • Mode 04/08 writes; CarDash is read-only.
  • Wi-Fi, USB and BLE adapters.
  • Cabin temperature.
  • Background OBD polling or background location.

2. Decisions

# 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 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 whenever it is present and fresh.

3. Permissions

Feature Manifest Runtime
Bluetooth 29–30 BLUETOOTH, BLUETOOTH_ADMIN (maxSdkVersion="30") install-time
Bluetooth 31+ BLUETOOTH_CONNECT requested from the Car data card
Weather INTERNET, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION location requested when the weather toggle is enabled

There is no BLUETOOTH_SCAN. The app lists bonded devices only and requests Bluetooth permission from the Car data 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 and the weather toggle are persisted in SettingsRepository.

4. Architecture

Kotlin
  TelemetryBridge  MethodChannel "com.wasp.cardash_launcher/telemetry"
    - listBondedDevices / isBluetoothEnabled / ensureBluetoothPermission
    - connectObd(mac) / disconnectObd / getObdState
    - ensureLocationPermission / getLocation (last-known or single fix + Geocoder)
  ObdService       one worker thread over BluetoothSocket/RFCOMM SPP
    - handshake ATZ, ATE0, ATL0, ATS0, ATSP0
    - request/response serialized, prompt-terminated
    - latest snapshot polled by Dart

Dart
  NativeTelemetryBridge  platform boundary
  ObdController          connection lifecycle, 1 s snapshot polling, status
  ObdEconomy             MAF/speed integrator with 5 km window
  WeatherController      toggle, permission, one-shot location, weather cache
  WeatherService         keyless Open-Meteo current temperature_2m
  TelemetryBridge models BluetoothDeviceInfo / LocationReading / ObdState
  SettingsRepository     obd.adapterAddress, weather.locationTemperature

The native ObdService polls speed, throttle and MAF 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.

5. Home UI

  • Temperature row immediately below the date:
    • OBD: Outside, 7°C
    • Weather: Sofia, 7°C (or Current location, 7°C)
    • Red below 3°C, otherwise normal ink.
    • OBD ambient is always preferred. If OBD is disconnected or has no ambient value, the location weather fallback is used when enabled and available.
    • If OBD has no temperature and weather is off/unavailable, no row is shown.
  • OBD card in the left column above the media-volume card, only while fresh telemetry exists:

    ● OBD-II                         LIVE
    44 km/h
    Throttle                     22%
    [========------------------]
    Rolling economy        7.5 L/100 km
    
  • The card and row disappear cleanly when off/no adapter/no fresh data. The 16-button grid keeps its own space.

6. Settings — Car data

  • OBD-II adapter: dropdown containing None and paired Bluetooth Classic devices. Find/Allow requests Bluetooth permission and refreshes the list.
  • Connection status: Off / Connecting / Connected / waiting for data / error.
  • Location temperature toggle: “Show temperature from current location if no OBD-II connected.” Enabling it asks for location permission.
  • Read-only note: CarDash never writes to the ECU.

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.

7. Weather fallback

WeatherController:

  1. Requires the toggle to be enabled and location permission granted.
  2. Gets one location fix through TelemetryBridge.getLocation.
  3. Reverse-geocodes a display name with Android Geocoder.
  4. Queries Open-Meteo:

https://api.open-meteo.com/v1/forecast?...&current=temperature_2m&timezone=auto

  1. Refreshes every 15 minutes while enabled.

Any failure clears the temperature and hides the row. No API key, account or coordinates are stored.

8. Failure and freshness

  • Missing PID → null, never zero.
  • OBD data older than 5 s → stale; hide live card and ambient.
  • Ambient -40/215 sentinel values are rejected.
  • Weather failure → no row.
  • Permission denial is a normal state; the Settings card shows the error and offers the relevant Allow action.
  • The OBD status is visible only in Settings; the dashboard stays quiet.

9. Testing

  • Dart unit tests cover the rolling economy math and the OBD card.
  • Settings persistence covers the adapter address and weather toggle.
  • The API 35 emulator verifies the location permission path, reverse geocoding, Open-Meteo fetch and the temperature row (Ukiah, 17°C during implementation).
  • The Android bridge compiles for API 29/35.
  • Not yet verified: a real ELM327 socket, PID responses, clone timing and reconnect behavior in a car. This is the main remaining soak test.

10. Decision log

  • 2026-10-29 — Classic SPP, bonded-only, read-only subset: speed, throttle, MAF economy, ambient.
  • 2026-10-29 — Added Open-Meteo/location fallback at the user's request; INTERNET and location permissions accepted for this feature only.
  • 2026-10-29 — Implemented in 0.6.0 with Car data Settings, live OBD card and temperature row; hardware verification deferred to a car.