# yaris-obd Bug Tracker Standalone bug/issue tracker. One `## BUG-XX` per issue. Numbering sequential. **Status**: `OPEN` → `IN PROGRESS` → `CLOSED` (with commit ref + verification). When CLOSED, move the entire entry to Resolved — don't duplicate. --- ## Open bugs ### BUG-17 — Server trip timestamps wrong after an offline period - **Status**: `OPEN` 2026-08-13 - **Phase**: 29 - **Symptom**: two trips from the 2026-08-13 drive have bad timestamps on the server: - Trip **25136** — time is wrong. - Trip **25137** — starts 09:59, then jumps to 14:xx after the first point. - **Cause (hypothesis)**: the Pi has no RTC, so while offline it runs on a stale `fake-hwclock` time; when NTP later re-syncs, the clock snaps forward, producing the timestamp jump mid-trip. Root cause is BUG-18. ### BUG-18 — Pi needs offline timekeeping (no RTC) - **Status**: `IN PROGRESS` 2026-08-14 - **Phase**: 29 - **Problem**: the Pi 3 has no real-time clock. Without internet (no NTP) the system clock is wrong across power cycles, corrupting tracking/trip timestamps (BUG-16/BUG-17). - **Progress 2026-08-14**: DS3231 module installed + working. Pi config done: `dtparam=i2c_arm=on` + `dtoverlay=i2c-rtc,ds3231` in `/boot/firmware/config.txt`, `i2c-tools` installed, `fake-hwclock` disabled, `i2c-dev` added to `modules-load.d`. The DS3231 now probes at `0x68` (`UU`), its 24C32 EEPROM at `0x57`, `/dev/rtc0` registered, and `hwclock -r` matches system time. (First scan was an empty bus — a data-line wiring issue, since resolved.) **Pending**: power-cycle persistence test — unplug, replug, confirm correct time at boot without NTP. Also: the charge diode was re-added during debugging and must be removed again for the CR2032. - **Fix plan (both, they complement each other)**: 1. **DS3231 RTC module (primary)** — battery-backed RTC on the free I²C bus (SDA pin 3, SCL pin 5, 3.3V pin 1, GND pin 6). Enable `dtparam=i2c_arm=on` + `dtoverlay=i2c-rtc,ds3231` in `/boot/firmware/config.txt`, install `i2c-tools`, disable `fake-hwclock`. Use a **CR2032** and first **desolder the module's charging resistor + diode** (cheap ZS-042-style boards charge the coin cell — unsafe for a CR2032; the well-known DS3231 charging-circuit issue). Gives correct time instantly at boot, ±2 ppm. 2. **SIM868 CR1220 RTC backup (secondary)** — the HAT has a CR1220 holder on the back (item 20). A CR1220 keeps the SIM868's internal RTC alive across power-off, enabling faster GNSS warm starts and letting the Pi optionally read the module time at boot (`AT+CCLK`) as an offline fallback. - Keep `systemd-timesyncd` for online NTP; fall back to the RTC (DS3231) and optionally GNSS time when offline. ### BUG-19 — Dashboard OBD values slow to appear while the car is running - **Status**: `OPEN` 2026-08-13 - **Phase**: 29 - **Symptom**: on the Pi dashboard, the speed/RPM/coolant/fuel/throttle cards stay on "—" for a long time after the page loads (or after ignition) before populating, even though the car is running and OBD is connected. - **Cause**: the value cards were populated **only** by socket.io push events from the OBD polling threads — the dashboard never pulled a current snapshot on load, so a freshly loaded page had to wait for the next poll tick (plus any reconnect/probe latency). `/api/obd/status` only returned the connection state, not the actual values, so there was no REST fallback either. - **Fix**: emit a full current-value snapshot on socket connect, and extend `/api/obd/status` to return live speed/RPM/coolant/fuel/throttle/MIL so the dashboard fills the cards immediately on load (and every 15 s) via REST. Needs in-car verification. --- ## Resolved ### BUG-15 — Phone can't host the hotspot and connect to the Pi's AP at once - **Status**: `CLOSED` 2026-08-13 - **Commit**: `ab79820` - **Resolution**: Confirmed a **phone-OS limitation**, not a Pi bug. A single phone can't cleanly be both the Pi's internet uplink (hotspot/AP host) and its WiFi client (on the Pi's AP) at the same time — doing so routes the hotspot's traffic back through the no-internet AP, creating a routing loop (`NameResolutionError` on uploads). - **Workaround (documented)**: the phone must be **LTE-only** (WiFi off) to serve as the Pi's uplink. Reach the Pi UI from that phone over the hotspot at `http://` (Settings → "In-car hotspot"), or from a second device on the AP. - **Pi-side hardening shipped**: `phone-hotspot` profile forces public DNS (`8.8.8.8`/`1.1.1.1`), and the Settings page surfaces the correct URL per uplink mode. ### BUG-16 — Trip missing from Pi local history (present on server) - **Status**: `CLOSED` 2026-08-13 - **Commits**: `e5ac14e`, `f5f20c3` - **Fix**: two root causes: 1. `connect_obd()` set `_car_ever_connected` **without a `global` declaration**, so the module-level flag was never set and `was_car_ever_connected()` always returned `False` — local trip building had been silently blocked ever since BUG-10 landed. Added the `global` declaration and now persist the flag to the settings table (`car_ever_connected`) so it survives reboots. 2. Speed-only rows (NULL GPS, from FEAT-12) made trips start/end with NULL coordinates, violating the `trips.*GPSX NOT NULL` constraint. The trip builder now uses the first/last GPS-bearing row for start/end coordinates, and skips a trip that never got any fix. - **Verification**: backfilled the persisted flag on the Pi (the car has been connected before), triggered a rebuild — the local `trips` table now contains the 2026-08-13 drive (e.g. a 48.5 km trip) plus several earlier trips that had been silently dropped. `trip_build_state` advanced to LAST_TRACKING_ID=7009. Timestamps for the 08-13 data are still wrong — that's BUG-17 (no RTC). ### BUG-13 — Server Web UI shows raw coordinates instead of geocoded location on trips - **Status**: `CLOSED` 2026-08-12 - **Commit**: `8309819` - **Fix**: Server `_geocode_cached()` now always returns a non-empty string with coordinate fallback when Nominatim/reverse_geocoder fail. `/api/geocode` always returns HTTP 200 with `{label}` (never 204). Batch endpoint includes all keys. Nominatim params + reverse_geocoder mode aligned with Pi. Pi also hardened against empty reverse_geocoder label. - **Verification**: Deployed to Unraid (Docker rebuild) and Pi (git pull + restart). Both healthy. Unraid now uses SSH deploy key for git fetch (was failing on HTTPS auth). ### BUG-14 — Geocode slow/unreliable — location labels fail to load during scrubbing - **Status**: `CLOSED` 2026-08-12 - **Commit**: `0ddfe39` - **Fix**: Ditched Nominatim entirely — it was slow (1 req/sec rate limit, ~4s timeouts) and often blocked/throttled from Docker/Cloudflare IPs. Replaced with reverse_geocoder exclusively: an offline Python library that maps lat/lon → city/province instantly with no network. JS `preload()` switched from N individual GET requests to single `POST /api/geocode/batch`. Server batch endpoint simplified to sequential loop with lru_cache + dedup. - **Verification**: `POST /api/geocode/batch` returns `{"Montreal, Quebec", "Longueuil, Quebec"}` instantly on Pi. Server Docker rebuilt and healthy. ### BUG-01 — WiFi/hotspot unreachable from phone while cell data is on - **Status**: `CLOSED` 2026-08-11 - **Fix**: Dual-radio — wlan0="yaris 911" at 10.42.0.1 (password "yaris911!"), wlan1=uplink. Never touches wlan0. Phone-hotspot auto-connect on wlan1 within ~60s, falls back to home-wifi. Settings page shows in-car access card. - **Verification**: iOS + Android connect to AP, `yaris.local` resolves. Phone-hotspot uplink tested: auto-connects when hotspot enabled, falls back when disabled. wlan0 AP stays up throughout. ### BUG-02 — Micro-USB power port on the Pi is physically damaged - **Status**: `CLOSED` 2026-08-11 - **Fix**: Hard-wired 5V/GND directly to GPIO header — red to Pin 2 (5V), black to Pin 6 (GND), bypassing the worn micro-USB port. - **Verification**: `vcgencmd get_throttled` returns `0x0` — no undervoltage, no throttling. Pi runs at full 1.2 GHz. GPS has fix. ### BUG-03 — DTC/MIL codes never persisted - **Status**: `CLOSED` 2026-08-11 - **Commit**: `e2f2314` - **Fix**: `save_dtc_state()` persists MIL+codes each poll. `/api/dtc` falls back to `get_persisted_dtc_state()` when OBD offline. Cleared codes tracked via IS_SET timestamps. - **Verification**: Deployed to Pi, `/api/dtc` returns persisted snapshot, stats show `active_dtc: 0`. ### BUG-04 — Server merges two trips into one - **Status**: `CLOSED` 2026-08-11 - **Commit**: `96fb897` - **Fix**: Replaced time-gap splitting with Pi's motion-aware logic: OBD > 1 km/h primary, GPS >= 8m × 3 consecutive fallback, 5-min inactivity gap. - **Verification**: Server trips cleared + recomputed. 17 trips on both Pi and server. ### BUG-05 — Server route replay speed_source always "gps" - **Status**: `CLOSED` 2026-08-11 - **Commit**: `e2f2314` - **Fix**: `"obd" if speed > 0 else "gps"` matching Pi logic. - **Verification**: Docker rebuild, `/health` OK LAN + Cloudflare. ### BUG-11 — Dashboard GPS shows "Stale fix" while Status shows "Live fix" - **Status**: `CLOSED` 2026-08-11 - **Commit**: `9733036` - **Fix**: `renderGpsStatus()` now reads `status.latitude`/`status.longitude` from the `/api/gps/status` response (not just socket events). Status page now uses the same 30s staleness threshold (`fix_age_seconds > 30` → "Stale fix") instead of calling any fix "Live" regardless of age. - **Verification**: Deployed to Pi, dashboard GPS card now shows lat/lon coordinates even when fix is stale. Both pages agree on fix status. ### BUG-06 — Server timestamps are shifted (naive local time stored as UTC) - **Status**: `CLOSED` 2026-08-11 - **Commit**: `7ce2a1e` (upload fix), manual migration on server - **Fix**: 1. `_to_tz_aware()` in `app_upload.py` converts naive SQLite timestamps to TZ-aware ISO before upload (`2026-08-10 19:27:30` → `2026-08-10T19:27:30-04:00`). 2. One-time SQL migration on Unraid: shifted 3,593 tracking rows +4h EDT, cleared deleted-trip markers, recomputed 43 trips from corrected data. - **Verification**: Server trips now show Aug 10 at 7:27 PM / 7:58 PM (was 3:27 / 3:58). ### BUG-12 — Dashboard OBD shows "—" while Status page shows correct OBD state - **Status**: `CLOSED` 2026-08-11 - **Commit**: `91281b1` - **Fix**: Added `/api/obd/status` endpoint. Dashboard calls `refreshObdStatus()` on load + every 15s. Socket events still update in real-time. Side fix: `Number()` wrap on API string lat/lon prevents crash. Socket `gps_location` now passes lat/lon to `renderGpsStatus` (`a4a92cc`). - **Verification**: Dashboard shows "Adapter only" matching Status page. GPS lat/lon display correctly. Confirmed on live Pi. ### BUG-02 — Micro-USB power port on the Pi is physically damaged - **Status**: `CLOSED` 2026-08-11 - **Fix**: Hard-wired 5V/GND directly to GPIO header — red to Pin 2 (5V), black to Pin 6 (GND), bypassing the worn micro-USB port. - **Verification**: `vcgencmd get_throttled` returns `0x0` — no undervoltage, no throttling. GPS has fix. Pi runs at full 1.2 GHz. ### BUG-07 — Trip replay on portal sometimes does nothing - **Status**: `CLOSED` 2026-08-11 - **Commit**: `fa93384` - **Fix**: Full rewrite of `static/js/history.js`: unified AbortController cancels fetch + all downstream rendering on trip switch; 300ms debounce prevents double-tap stacking; loading spinner on map + `.table-active` row highlight give clear feedback; geocode preload starts immediately before map rendering so cache is warm for the scrubber; `signal.aborted` guards after every async step (route build, fitBounds, timeline init). - **Verification**: Deployed to Pi and server. Rapid trip-switching no longer freezes. Verified on both platforms 2026-08-11. ### BUG-08 — No trip deletion on local Pi - **Status**: `CLOSED` 2026-08-11 - **Commit**: `c5c478b` - **Fix**: `deletable` macro, `window.confirmDelete`, `DELETE /api/trip/`, configurable `data-delete-url` in shared `history.js`. Raw tracking preserved. - **Verification**: Trip 1967 deleted (18→17 trips), 2028 tracking rows preserved. ### BUG-09 — Server trip scrubber geocoding is slow - **Status**: `CLOSED` 2026-08-11 - **Fix**: `preloadGeocodes()` batch-fetches all unique coords (concurrency 4) on trip load. `geocodePoint()` checks in-memory cache first. - **Verification**: `preloadGeocodes` present in history.js on both Pi and server Docker container. ### BUG-10 — GPS-only false trips when car not connected - **Status**: `CLOSED` 2026-08-11 - **Fix**: `_car_ever_connected` flag in `app_obd.py`. `build_trip_summaries()` returns empty list when car was never connected. - **Verification**: Pi bench-test shows 0 trips. No OBD = no GPS-only trips.