# CarDash — OBD-II and temperature design note _Status: implemented in CarDash 1.0.3; OBD hardware still needs a real-car test. Last updated: 2026-10-30_ ## 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. 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. ### 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 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. | ## 3. Permissions | 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`. ## 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 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` 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, only while the Temperature switch is on: - OBD source: `Outside, 7°C` - Weather source: `Sofia, 7°C` (or `Current location, 7°C`) - Red below 3°C, otherwise normal ink. - OBD ambient is preferred while its source switch is on. 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. - **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. - The card and row disappear cleanly when off/no adapter/no fresh data. The 16-button grid keeps its own space. ## 6. Settings cards **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. - Bluetooth-off action: **Open Bluetooth settings**. - Read-only note: CarDash never writes to the ECU. - This card contains adapter settings only. **Speed** - Show/hide switch for the speed card. - While an OBD-II adapter is selected: **Use OBD-II for speed**. Off selects GPS. - The source switch is hidden while no adapter is selected; GPS is then used. **Temperature** - Show/hide switch for the temperature row. - While an OBD-II adapter is selected: **Use OBD-II for temperature**. Off selects GPS + Open-Meteo weather. - Enabling temperature or choosing the weather source asks for location permission. OBD temperature still works if permission is denied. 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 Temperature switch to be on 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?...¤t=temperature_2m&timezone=auto` 5. 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 Temperature card shows the weather error while OBD temperature can still work. - The OBD status is visible only in Settings; the dashboard stays quiet. ## 9. Testing - Dart unit tests cover the rolling economy math, the OBD card and the speed/temperature preference controller. - Settings persistence covers the adapter address, visibility switches, source choices and weather preference. - 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. - 2026-10-30 — Split Settings into OBD-II, Speed and Temperature cards, added independent visibility toggles and OBD/GPS-weather source switches. - 2026-10-30 — Retired the two-minute process-start onboarding hint in favor of a ten-minute first-install window that never returns after an upgrade.