Files
yaris-obd/BUGS.md
T

226 lines
13 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-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://<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.