Files
yaris-obd/BUGS.md
T

239 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-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-21 — OBD speed drops out mid-drive, replay shows 0 km/h (GPS-only)
- **Status**: `CLOSED` 2026-08-14
- **Commit**: `PENDING`
- **Fix**: the Pi's OBD adapter (ELM327) stopped returning speed for ~20 min on 2026-08-13
(last OBD reading 22:23:50 UTC, back at 22:43:41 UTC), so the portal replay flatlined at
0 km/h for that stretch. The server's `get_trip_route()` now mirrors the Pi's `route_points`
GPS-speed fallback — when OBD speed is missing it derives speed from the previous point's
movement (haversine / elapsed time, ≥8 m, ≤220 km/h). The Pi's own replay already did this;
only the portal was missing it.
- **Verification**: trip #9 points at 22:23:55 previously returned speed 0.0 — now return
GPS-derived speeds (e.g. 61.9 km/h at 22:23:55, labelled `gps`). API rebuilt + healthy.
- **Follow-up**: investigate why the OBD adapter dropped for ~20 min (reconnect on stalled
reads).
### BUG-20 — Server trip IDs inflate far beyond the real trip count
- **Status**: `CLOSED` 2026-08-14
- **Commit**: `9af71e2`
- **Fix**: `trips.id BIGSERIAL` burned a sequence value on every upsert in
`compute_trips_for_device()` (which runs after every upload batch), so IDs climbed far past
the real trip count. Now the sequence is clamped to `MAX(id)` after each recompute
(`server/modules/db.py`), and a one-time migration (`server/sql/migrate_phase29_trip_ids.sql`)
renumbered existing trips compactly and reset the sequence.
- **Verification**: before — `COUNT=10`, `MAX(id)=27091`; after — `MIN(id)=1`, `MAX(id)=10`,
sequence `last_value=10` (next insert gets 11). API container rebuilt and healthy.
### BUG-18 — Pi needs offline timekeeping (no RTC)
- **Status**: `CLOSED` 2026-08-14
- **Commit**: `bf4f3d3`
- **Fix**: DS3231 RTC module installed on the free I²C bus (SDA pin 3, SCL pin 5, 3.3V pin 1,
GND pin 6) with a CR2032 (charge diode removed). Pi config: `dtparam=i2c_arm=on` +
`dtoverlay=i2c-rtc,ds3231` in `/boot/firmware/config.txt`, `i2c-tools` installed,
`fake-hwclock` disabled, `i2c-dev` persisted via `modules-load.d`. CR1220 also installed in
the SIM868 HAT holder (secondary RTC backup).
- **Verification**: DS3231 probes at `0x68` (`UU`), its 24C32 EEPROM at `0x57`, `/dev/rtc0`
registered. Power-cycle test passed — after a full unplug/replug the boot log reads
`setting system clock to 2026-08-14…` from the RTC (was `2000-01-01` before), and
`hwclock -r` matches system time; the `SET TIME!` recovery line no longer appears (stable
oscillator on CR2032). (Debugging note: the first scans were an empty bus due to a data-line
wiring issue, resolved during re-soldering.) SIM868 HAT RTC was also set to the correct time
via `AT+CCLK` (was factory-default 2004) — its CR1220 hold will be confirmed on the next
power cycle.
### BUG-17 — Server trip timestamps wrong after an offline period
- **Status**: `CLOSED` 2026-08-14
- **Commit**: `bf4f3d3`
- **Fix**: root cause was BUG-18 — no RTC, so offline the Pi ran on a stale `fake-hwclock`
time and NTP snapped the clock forward mid-trip. Fixed by installing the DS3231 (BUG-18).
- **Verification**: RTC power-cycle test passed (BUG-18). Historical trips 25136/25137 keep
their bad timestamps (raw tracking rows were recorded with a wrong clock and can't be
retroactively corrected) — future trips will be correct.
### 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://<pi-hotspot-ip>` (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/<id>`, 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.