diff --git a/BUGS.md b/BUGS.md new file mode 100644 index 0000000..61012b7 --- /dev/null +++ b/BUGS.md @@ -0,0 +1,190 @@ +# yaris-obd Bug Tracker + +Standalone bug/issue tracker for the yaris-obd project, kept **separate from `PLAN.md`**. Use this +file to record, track status, and hand off bugs to another agent/session. `PLAN.md` still summarizes +bug-fix progress in its phase sections (and Phase 26 is the dedicated road-test bug-fix phase), but +the authoritative, issue-by-issue record lives **here**. + +## How to use this tracker + +- **File format**: one `## BUG-XX` section per issue. Keep the numbering sequential. +- **Status field**: `OPEN` → `IN PROGRESS` → `FIXED` (commit ref) → `CLOSED` (deployed + verified) + or `WONTFIX`/`DUP` as appropriate. +- **Relate to phases**: each entry's `Phase` field links a bug to the relevant `PLAN.md` phase so an + agent can find the surrounding context and acceptance criteria. +- **When fixed**: keep the original symptom/impact recorded (don't delete history), set status to + `FIXED`, add the commit SHA in the `Fix` field, then move to `CLOSED` after deploy/verify. Also + drop a one-line mention in the corresponding `PLAN.md` phase. +- **For future bugs**: add new `## BUG-XX` entries here rather than only burying them in chat + history. Keep them SMALL and one-issue-per-entry so they are easy to pick up and verify. + +--- + +## Open bugs + +### BUG-01 — WiFi/hotspot unreachable from phone while cell data is on (and wrong documented gateway) +- **Status**: `OPEN` +- **Severity**: Medium (usability of the in-car hotspot from a phone) +- **Area**: Networking / Pi hotspot (`yaris-uplink`, NetworkManager shared AP, docs) +- **Phase**: Phase 26 +- **Symptom**: While a phone is connected to the Pi's no-internet hotspot and cell data is on, the + phone cannot load `yaris.local`, `10.42.0.1`, **or** the Pi's DHCP address at all. With cell data + disabled, `http:///` loads, but `yaris.local` and `10.42.0.1` still do not. The working + address seen was `10.112.<...>`. +- **Root cause (confirmed)**: Phone-OS "smart network switching" — with a no-internet WiFi network + associated and cellular available, the OS keeps cellular as the whole-device default route, so no + traffic (even a plain page navigation or `fetch()`) reaches the Pi hotspot. Disabling cell data + forces the hotspot WiFi to become the default network. This is the same OS-level ceiling + documented in Phase 11/22. Separately, the actual NetworkManager shared-AP subnet is `10.112.0.x`, + **not** the documented `10.42.0.1`, and `yaris.local` mDNS isn't resolved from the phone on the + Pi AP. +- **Fix scope / actions**: + - Make the documented/reachable address correct (surface the Pi's real DHCP-assigned address in + the UI / status page rather than hardcoding `10.42.0.1`). + - Extend the `yaris.local` unicast (shared-dnsmasq) fallback to the AP subnet so it resolves from + a phone on the Pi hotspot. + - Clearly document the cell-data limitation and the workaround (disable cell data / "smart + network switching"). +- **Acceptance**: phone on the Pi hotspot can load the web UI via a documented, correct address + (optionally `yaris.local`), and the cell-data caveat is documented. + +--- + +### BUG-02 — Micro-USB power port on the Pi is physically damaged +- **Status**: `OPEN` +- **Severity**: Hardware (reliability/power) +- **Area**: Hardware / power +- **Phase**: Phase 26 +- **Symptom**: The Pi's micro-USB 5V power connector is worn/damaged and no longer makes a reliable + connection. Power is likely to drop under vibration in the car. +- **Root cause**: Physical wear on the connector. +- **Fix scope / actions**: No code. Owner hard-wires 5V and GND directly to the Pi's GPIO header + (pins 2/4 for 5V, 6/9/14/20/25/30/34/39 for GND) with a suitable PSU, bypassing the micro-USB + port. Confirm `vcgencmd get_throttled` shows no current undervoltage after rewiring (the Phase + 19/20 alerts monitor this). +- **Acceptance**: Stable power with no undervoltage/throttling under load. + +--- + +### BUG-03 — DTC/MIL codes are never persisted; lost on OBD disconnect or reboot +- **Status**: `OPEN` +- **Severity**: Medium (lost diagnostic data; also a stats bug) +- **Area**: `modules/app_obd.py`, `modules/app_sql.py`, `get_overview_stats` +- **Phase**: Phase 26 +- **Symptom**: Stored DTC trouble codes and MIL state live only in the in-memory `dtc_codes` global + in `app_obd.py`. They vanish as soon as OBD disconnects or the Pi reboots. Separately, + `get_overview_stats` queries a table named `dtc_codes` that does not exist (the created table is + `dtc`), so the post-road-test state may be wrong/broken. +- **Root cause**: The SQLite `dtc` table is created in schema but is never written to or read from + by any code path. No DTC persistence exists at all. +- **Fix scope / actions**: + - Persist MIL + DTC codes to the `dtc` SQLite table on each successful poll. + - Read back from SQLite when OBD is disconnected so last-known codes stay visible. + - Fix `get_overview_stats` to query the real `dtc` table (and use current MIL/DTC state). + - Add a "cleared/since" concept so a code that was cleared is distinguishable from one still set. +- **Acceptance**: Codes set during a drive survive a power cycle / OBD disconnect and appear on the + DTC page and overview stats. + +--- + +### BUG-04 — Server merges two separate trips into one (motion boundary mismatch) +- **Status**: `OPEN` +- **Severity**: Medium (incorrect server trip history vs the Pi) +- **Area**: `server/modules/db.py` `compute_trips_for_device` +- **Phase**: Phase 26 +- **Symptom**: Two distinct drives (parked in between) appear as a single merged trip on the remote + portal, while the Pi correctly reports them as separate trips. +- **Root cause**: The Pi splits trips by **motion** (OBD wheel speed + sustained GPS displacement, + with a 5-min motion gap). The server splits only by a **pure time gap** (>5 min) and filters by + duration/50 m, so parked idle tracking rows bridging two drives get combined into one trip. +- **Fix scope / actions**: Mirror the Pi's motion-aware trip-boundary logic on the server so the + two systems agree. Note this may re-split/recompute existing server trips — get owner sign-off + before recomputing, and re-run `scripts/recompute_trips.py` after the fix. +- **Acceptance**: A real drive with a parked gap produces the same number of trips on the server + as on the Pi. + +--- + +### BUG-05 — Server route replay reports `speed_source: "gps"` even when OBD speed is present +- **Status**: `OPEN` +- **Severity**: Low (display/metadata) +- **Area**: `server/modules/db.py` `get_trip_route` +- **Phase**: Phase 26 +- **Symptom**: Server route replay always labels points with `speed_source: "gps"`, even though the + points carry real OBD `speed`. The Pi's `route_points` correctly uses `"obd"` when speed > 0. +- **Root cause**: `get_trip_route` hardcodes `speed_source: "gps"` rather than deriving it from the + per-point speed value. +- **Fix scope / actions**: Mirror the Pi's logic (`"obd"` when speed > 0, otherwise `"gps"`) in the + server route response. +- **Acceptance**: Server route points report `obd` speed source where wheel speed was recorded. + +--- + +### BUG-06 — Server timestamps are shifted (Postgres stores naive local time as UTC) +- **Status**: `OPEN` +- **Severity**: High-ish (all server trip times / boundaries off by the EDT offset) +- **Area**: Pi upload (`modules/app_upload.py` / SQL), `server/sql`, `server/modules/db.py`, portal + display +- **Phase**: Phase 26 +- **Symptom**: Server shows trip times (and effectively trip boundaries/comparisons against the Pi) + shifted by the Montreal-timezone-to-UTC offset (~4-5 hours depending on DST). +- **Root cause**: `tracking_points.recorded_at` is `TIMESTAMPTZ`, but the Pi sends **naive local + (Montreal) time** (`datetime.now()`) with no offset. Postgres (UTC container timezone) interprets + that naive string as UTC. +- **Fix scope / actions** (delicate — touches sending, storage, and display): + - Pi should send timezone-aware timestamps in local Eastern time (or explicit UTC). + - Server should store/read as `America/Toronto` (or consistent UTC) and display in Eastern. + - Optional one-time migration to correct already-stored rows (depends on offset at insert time — + needs a decision: re-map by DST window or accept a best-effort correction). Rebuilding the + server `trips` table may be needed. **Get owner sign-off on migrating existing data.** +- **Acceptance**: New data displays at the correct local time on the portal; existing shifted rows + are corrected (or explicitly accepted as-is if the owner opts out of migration). + +--- + +### BUG-07 — Trip replay on the portal sometimes does nothing +- **Status**: `OPEN` (needs reproduction/diagnostics) +- **Severity**: Low/Medium (intermittent UI) +- **Area**: `static/js/history.js` (shared Pi+server), server `/api/v1/portal/trip/` +- **Phase**: Phase 26 +- **Symptom**: Clicking a trip to replay on the `/history` page intermittently does nothing — no + route renders, no error shown. +- **Root cause**: Not yet isolated. Plausible contributors: an API/DB race (`recompute_trips` + running concurrently with a route read), DB lock, or clicking before the map is ready. Note + `history.js` uses shared parsing that expects space-separated Pi timestamps and `"T"`-separated + server ones — verify both. +- **Fix scope / actions**: Add targeted diagnostics (log/reproduce) before fixing. Check map + readiness, error handling on the trip-fetch, and the shared timestamp parsing. Add an explicit + "failed to load route" state instead of silent inaction. +- **Acceptance**: Replay is reliable; any failure surfaces a visible error rather than doing + nothing. + +--- + +### BUG-08 — No trip deletion on the local Pi (only on the remote portal) +- **Status**: `OPEN` +- **Severity**: Medium (feature parity: delete trips locally) +- **Area**: Pi `templates/components.html`, `templates/base.html`, `templates/history.html`, + `static/js/history.js`, `app.py` +- **Phase**: Phase 26 +- **Symptom**: The Pi `/history` page has no way to delete a trip. The remote portal does. +- **Root cause**: Several Pi pieces are missing compared to the server: + 1. Pi `components.html` `data_table` macro lacks the `deletable` arg that emits + `data-deletable="1"` (the server's macro has it). + 2. Pi `base.html` does not define `window.confirmDelete` (the server's does). + 3. Pi `history.js` hardcodes the **server** delete endpoint + `/api/v1/portal/trip/` — which does not exist on the Pi. + 4. There is no `DELETE /api/trip/` route on the Pi at all. +- **Fix scope / actions**: Add all four pieces on the Pi — the `deletable` macro arg, the + `window.confirmDelete` helper, a `DELETE /api/trip/` route that removes only the derived trip + record (keeping the raw `tracking` data), and make the delete endpoint configurable in + `history.js` (e.g. via a data attribute like the tile URL) so the same JS works on Pi and server. +- **Acceptance**: The Pi `/history` page can delete a trip with confirmation; raw GPS data is + preserved; the server portal is unaffected. + +--- + +## Resolved bugs + +(No entries yet — resolved-and-fixed bugs land here, oldest→newest. Keep the bug's original +symptom text intact and add the fix/closure details.) diff --git a/PLAN.md b/PLAN.md index 96c47f5..39c6225 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1400,7 +1400,7 @@ including two UX polish passes and multiple bug-fix rounds. **Roadmap ordering note (2026-08-10):** the late phases are intentionally sequenced as Phase 25.5a–25.5d (configuration/sync/status work) -> Phase 25 (real-car acceptance gate) -> -Phase 26 (Android, always last). +Phase 26 (road-test bug fixes) -> Phase 27 (Android, always last). ### Phase 25.5a: Device configuration sync backend — ✅ COMPLETE (connection-driven server sync) **Server API and Pi sync thread implemented.** Server stores device config; Pi fetches when internet available and applies changes without restart. @@ -1714,7 +1714,14 @@ architecture. `/` HTML places `Overview` before `Live GPS`. --- -### Phase 25: Pre-install Yaris 2013 compatibility test — 🚧 PLANNED (core-system gate) +### Phase 25: Pre-install Yaris 2013 compatibility test — ✅ DONE (owner road test; full checklist not followed) +**Owner conducted the in-car road test and checked for bugs. Per explicit owner instruction this +phase is marked complete — however, the full Phase 25 acceptance checklist was NOT rigorously +worked through item-by-item (an engineer was not present; several checklist items were skipped or +only informally observed). Treat the system's compatibility with the 2013 Yaris as validated by +the owner's practical drive, not as a documented item-by-item pass.** Bugs surfaced by the road +test are cataloged in `BUGS.md` and tracked for fixing in Phase 26. The former Phase 26 Android +slot was renumbered to **Phase 27 (always last)** to make room — see the roadmap note below. **Added 2026-08-09; intentionally immediately before the Android app.** Bench tests, synthetic routes, attached-hardware tests, and stationary Pi runs cannot prove the complete system works when temporarily connected to and powered by the actual 2013 Toyota Yaris. This phase is the @@ -1725,20 +1732,38 @@ cable routing, trim work, and final installation are explicitly outside the road handled by the owner after this phase passes. Prepare a temporary, removable test setup before driving: -- Connect the Pi, SIM868 HAT/antennas, USB OBD adapter, dashcam, and representative intended power +- ~~Connect the Pi, SIM868 HAT/antennas, USB OBD adapter, dashcam, and representative intended power source without permanently mounting or routing anything. Secure every temporary component and cable so it cannot interfere with pedals, steering, airbags, visibility, occupants, or loose-item - safety during the controlled drive; remove the setup after testing. -- Resolve the Phase 19/20 undervoltage/throttling warning before the test; confirm + safety during the controlled drive; remove the setup after testing.~~ — ✅ **DONE** (owner set up + the temporary test rig). +- ~~Resolve the Phase 19/20 undervoltage/throttling warning before the test; confirm `vcgencmd get_throttled` shows no current power fault at idle and under load with the temporary - representative power setup. This validates electrical compatibility, not final cable routing. -- Back up the Pi SQLite database and record baseline row/trip/video/upload counts on the Pi and + representative power setup. This validates electrical compatibility, not final cable routing.~~ — + ⚠️ **OPEN — NOT DONE.** The Phase 19/20 undervoltage/throttling warning was **not** resolved + before the test. The intended power source is the **cigarette-lighter USB charger**, with the + 5V/GND to be **hard-wired onto the Pi's GPIO header** (bypassing the worn micro-USB port — see + BUG-02). Whether the cigarette-lighter USB supplies clean, non-undervolting 5V under the Pi's + load still needs to be verified. **Action**: hard-wire 5V/GND to the GPIO header, then run + `vcgencmd get_throttled` at idle and under load and confirm **no current** fault before + declaring the power source adequate. If the lighter charger undervolts, it is **not** a + sufficient power source and a higher-rated/supported PSU must be chosen. (Cigarette-lighter + USB alone, on a worn/loose connector, is the most likely culprit for residual throttling.) +- ~~Back up the Pi SQLite database and record baseline row/trip/video/upload counts on the Pi and remote server. Use a uniquely timestamped test window so generated records can be reconciled - without deleting unrelated history. -- Verify the service, watchdog, storage mounts, hotspot, `http://yaris.local/`, alert engine, GPS - antenna view, dashcam recording mode, free space, and remote server health before moving. -- Use a second person for UI/log observations while the vehicle is moving, or record diagnostics - for review afterward. The driver must not operate or troubleshoot the UI while driving. + without deleting unrelated history.~~ — ⚠️ **SKIPPED** (owner: "didn't do it but don't very + care"). Acceptable to skip the pre-test backup/baseline, but be aware there is now **no + pre-test record** to reconcile test drive rows against, and no pre-drive SQLite backup exists. +- ~~Verify the service, watchdog, storage mounts, hotspot, `http://yaris.local/`, alert engine, GPS + antenna view, dashcam recording mode, free space, and remote server health before moving.~~ — + 🟡 **PARTIAL.** Pre-move verification was done and the hot-spot is connectable, but + **`yaris.local` does not resolve** on the phone → tracked as **BUG-01**. Everything else on this + line checked out (service/watchdog/mounts/free space/remote health) per the owner. +- ~~Use a second person for UI/log observations while the vehicle is moving, or record diagnostics + for review afterward. The driver must not operate or troubleshoot the UI while driving.~~ — + ⛔ **SCRATCHED** (owner: "will do it solo"). **Safety note kept**: the driver must NOT operate or + troubleshoot the UI while driving; solo testing relies on recording diagnostics for later + review. Run a controlled route containing ignition-off/on, stationary idle, low-speed streets, normal road speed, several complete stops, turns, a short GPS-obstructed segment if safely available, and a @@ -1747,22 +1772,34 @@ clean trip end: adapter firmware, and verify real speed/RPM/coolant/fuel/throttle/MIL/DTC values. Compare wheel speed against the instrument cluster at several safe speeds. Record unsupported PIDs (especially odometer PID A6) as capabilities, not failures, and verify reconnect after ignition cycling and a - deliberate USB disconnect/reconnect. + deliberate USB disconnect/reconnect. — ✅ **DONE** (owner: "seems to work — OBD connects, DTC + codes working, throttle working, speed, etc."). Negotiabd protocol/firmware values not explicitly + logged, and odometer PID A6 support remains unconfirmed (expected unsupported on the 2013 Yaris — + see Phase 24.6). - **GPS and motion logging:** confirm fixes while stationary and moving, route coordinates on the offline map, OBD-speed-first motion detection, GPS displacement fallback when OBD is deliberately - unavailable, one-minute idle heartbeat behavior, and no false trip from stationary GPS drift. + unavailable, one-minute idle heartbeat behavior, and no false trip from stationary GPS drift. — + ✅ **DONE** (owner: "seems to work for the trip"). **Cross-ref:** the *server-side* trip-boundary + mismatch (BUG-04) is the known follow-up. - **Trip boundary/replay:** after the inactivity timeout, verify exactly one trip (or the expected number for deliberate ignition gaps), correct start/end time and coordinates, plausible distance/average/max speed, km/mi and km/h/mph values, route polyline, start/end markers, timeline - scrubber, play/pause marker position, and stopped portions of the route. + scrubber, play/pause marker position, and stopped portions of the route. — + 🟡 **PARTIAL / bug reported.** Local replay observed OK, but the server-side trip-splitting and + replay issues are tracked in **BUG-04** (server merges two trips) and **BUG-05** (server replay + `speed_source`), with **BUG-06** (timezone shift affecting times) also relevant. - **Local web UI:** test the final Phase 23 interface on the actual phone over the Pi/phone network at `http://yaris.local/`; verify the explicit **In-car / Local Pi** identity, dashboard telemetry, DTC page, trip history, dashcam library, settings, alerts, responsive layout, reconnect behavior, - and no new browser console/API errors. + and no new browser console/API errors. — + 🟡 **PARTIAL / bug reported.** Reaching the UI over the Pi hotspot is blocked by `yaris.local` + not resolving on the phone → **BUG-01**. Other local UI pages work once reachable. - **Dashcam workflow:** create a known short real clip, switch the camera safely into USB storage mode, detect/list it without confusing the OBD adapter, import only that selected file, verify thumbnail/playback/Range seeking, preserve the source until checks finish, and confirm the camera - returns to recording afterward. Test deletion only with the disposable clip. + returns to recording afterward. Test deletion only with the disposable clip. — + ⏳ **DEFERRED** (owner: "will test later stages"). Not yet exercised as part of this test; remains + a follow-up for the Phase 26 bug-fix/verification pass. - **Alerts:** safely exercise conditions that can be simulated without damaging hardware (upload backlog, temporary GPS loss while OBD reports motion, and disposable threshold overrides). Confirm local bell transition/recovery/cooldown behavior and offline alert-state reconciliation @@ -1771,12 +1808,31 @@ clean trip end: transport can reliably deliver ntfy notifications while WiFi/Ethernet is unavailable, including authentication, timeout, retry, and recovery. If that cannot be made reliable on the actual modem/network, remove the ntfy feature and its settings rather than retain a transport that fails - in the only situation where it is useful. + in the only situation where it is useful. — + 🟡 **PARTIAL / done in part.** Owner reports alerts "seem to work for engine and DTC codes + + power". The SIM868 **ntfy path remains unverified** (no real SIM on the modem yet, so the + "determine whether the SIM868 transport can reliably deliver ntfy" sub-item is still open). - **Power/reliability:** perform multiple normal ignition/power cycles, confirm automatic boot, service/watchdog startup, SIM868 power-on, OBD/GPS recovery, no SQLite corruption, and no current undervoltage/throttling. The deferred Phase 14 clean-shutdown limitation must be explicitly accepted or resolved with representative delayed-power/ignition-sense hardware before declaring - the design ready for permanent installation. + the design ready for permanent installation. — + 🟡 **PARTIAL — Pi logs checked 2026-08-10 (at home, car not connected).** Verified from the live + Pi: + - `yaris-obd.service` **active**; uptime 2:48h with **no crash/restart** in the current boot + window (systemd auto-restart + the 10s hardware watchdog did not need to fire since startup). + - `vcgencmd get_throttled` → **`0x50000` = NO current undervoltage right now** (only the + historical "occurred" bits 0x40000/0x10000 remain set). Confirms the Pi is not *currently* + undervolting on whatever power is connected at home, but does not prove the in-car + cigarette-lighter source yet (re-check under load in the car after hard-wiring — see the open + power item above and BUG-02). + - OBD reconnect loop logging as designed ("handshake succeeded / ECU did not respond" = car not + on/not connected here). Uploads syncing fine ("sent N tracking rows"). + - No SQLite corruption or tracebacks in the log tail. + **Still open**: a real multi-ignition-cycle verification *in the car* (boot recovery, watchdog + restart under power loss, OBD/GPS recovery, no corruption) with the final hard-wired power + source has not been demonstrated. The Phase 14 clean-shutdown limitation remains **accepted** + (delayed-power / ignition-sense hardware not yet present). Verify the complete remote path after connectivity returns: - Confirm every test-window tracking row uploads exactly once and the selected dashcam clip resumes @@ -1786,9 +1842,12 @@ Verify the complete remote path after connectivity returns: vehicle-scoped trip summary/replay, route and timeline agreement with the local Pi, archived clip thumbnail/playback/Range seeking/download, synchronized alert history/current state without duplicate transitions after an offline interval, and absence of local-only OBD/cellular/Pi - controls. + controls. — + 🟡 **PARTIAL.** Owner can connect to the remote server; the portal is reachable. The main + blocker is the **Pi hotspot** reachability issue (**BUG-01**), which affects exercising the + portal from the in-car phone. Server-side trip/replay/time issues (BUG-04/05/06) also remain. - The Android companion is intentionally outside this core acceptance gate and remains the final, - low-priority Phase 26. Its own hotspot/cellular binding, trip display, and disposable clip relay + low-priority Phase 27. Its own hotspot/cellular binding, trip display, and disposable clip relay require separate real-phone/in-car acceptance when that phase is implemented. Acceptance requires a written result for every item, captured negotiated protocol/PID support, @@ -1800,7 +1859,54 @@ phase roadmap. --- -### Phase 26: Native Android companion app — 🚧 PLANNED (low priority, always last) +### Phase 26: Road-test bug fixes — 🚧 PLANNED +**Renumbered/added 2026-08-10 after the Phase 25 owner road test.** This phase (the former Phase 26 +Android slot, which is now **Phase 27**) is a targeted bug-fix pass for the defects surfaced by the +in-car road test. Each item references its tracking entry in `BUGS.md`; distinct fixes should be +committed individually with a `fix(bug-N): ...` prefix and each closed out in `BUGS.md` as it +lands. The current known issues from the road test (also recorded in `BUGS.md`): + +1. **BUG-01 (WiFi/hotspot reachability).** While cell data is on, a phone connected to the Pi's + no-internet hotspot cannot load `yaris.local`, `10.42.0.1`, or the Pi's DHCP address at all — + the phone OS keeps cellular as the default route (Phase 11/22 "smart network switching" + behavior). It only works once the user disables cell data, then `http:///` loads but + `yaris.local` and `10.42.0.1` still do not. Also: the live hotspot subnet is `10.112.0.x`, not + the documented `10.42.0.1`. Fix scope: make the documented/reachable address correct, surface + the real DHCP address in the Pi UI, document the cell-data behavior, and see if `yaris.local` + unicast fallback can be extended to the AP subnet. +2. **BUG-02 (micro-USB power port damaged).** Hardware-only (worn power connector). Action is + documentation + owner hard-wiring 5V/GND to the GPIO header pins; no code. +3. **BUG-03 (DTCs not persisted).** The SQLite `dtc` table is created but never written or read; + DTC codes/MIL live only in memory in `app_obd.py` and vanish on OBD disconnect/reboot. + `get_overview_stats` also queries a non-existent `dtc_codes` table. Fix: persist on each poll, + read back when disconnected, fix the stats query, add a "cleared/since" concept. +4. **BUG-04 (server merges two trips into one).** The Pi splits trips by *motion* (OBD wheel + speed + sustained GPS displacement, inactivity gap); the server splits only by *time gap* and + filters by duration. Parked idle tracking rows bridge two drives into one server-side trip. + Fix: mirror the Pi's motion-boundary logic server-side. +5. **BUG-05 (server replay speed_source).** Server `get_trip_route` hardcodes `speed_source: "gps"` + even when OBD speed is present (it already returns raw `speed`). Fix: mirror the Pi's + `obd if speed>0 else gps` logic. +6. **BUG-06 (server timezone is UTC-shifted).** `tracking_points.recorded_at` is `TIMESTAMPTZ` + but the Pi sends naive local (Montreal) time with no offset; Postgres (UTC container) treats + it as UTC, so server times/trip boundaries are off by the EDT offset. Fix: Pi sends + timezone-aware timestamps; server displays/stores in `America/Toronto`; optional one-time + migration to correct already-stored rows. +7. **BUG-07 (trip replay sometimes does nothing).** Intermittent `/history` replay failure — + needs reproduction/diagnostics (likely an API/DB race or map-not-ready timing). Add targeted + diagnostics before fixing. +8. **BUG-08 (no trip deletion on the local Pi).** The Pi's `components.html` `data_table` macro + lacks the `deletable` arg, `base.html` lacks `window.confirmDelete`, `history.js` hardcodes the + *server* delete endpoint, and there is no `DELETE /api/trip/` route on the Pi. Fix: add all + four pieces and make the delete endpoint configurable in `history.js`. + +**Acceptance for Phase 26:** every `BUGS.md` entry in scope is fixed, regression-tested, deployed, +marked resolved, and the corresponding fix recorded here. + +--- + +### Phase 27: Native Android companion app — 🚧 PLANNED (low priority, always last) +**Renumbered from former Phase 26 on 2026-08-10 to make room for the road-test bug-fix phase.** Revives the phone-relay goal (Phase 11/12) properly this time, using a real native app instead of a web page - the only way to actually hold a WiFi connection to the Pi's hotspot and a cellular connection to the internet open simultaneously (`ConnectivityManager.bindProcessToNetwork()`, diff --git a/readme.md b/readme.md index 02159c8..123b1dc 100644 --- a/readme.md +++ b/readme.md @@ -197,7 +197,9 @@ rm db/sql/quoije_Yaris2013.db The build is now at the endgame stage: the Pi app, remote server, and device-management/sync work are implemented and verified on the real Pi/unraid setup. The remaining roadmap phases are the -temporary real-vehicle acceptance test and the low-priority Android companion. +road-test bug-fix pass (Phase 26) and the low-priority Android companion (Phase 27). The owner has +already completed the Phase 25 real-vehicle test; the bugs it surfaced are tracked in +[BUGS.md](./BUGS.md). - **Phases 1–23.5**: core Pi system — GPS, OBD, dashcam, trip history, web UI redesign, WiFi upgrade, cellular fallback, alerts, settings, upload - **Phase 24**: remote web portal at `https://yaris.ceaf.dev/` — login-protected, trip history with CARTO live map, dashcam archive, delete, overview stats @@ -213,8 +215,8 @@ temporary real-vehicle acceptance test and the low-priority Android companion. main remote overview/history/dashcam browsing views still follow one configured `DEVICE_NAME` until a later portal-wide device selector/filter is added -**Next**: Phase 25 — temporary real-vehicle test in the 2013 Yaris (see [PLAN.md](./PLAN.md) for -the full acceptance checklist). Phase 26 (Android companion app) follows after that. +**Next**: Phase 26 — road-test bug fixes from the Phase 25 in-car test (see [BUGS.md](./BUGS.md) +for the tracked issues). Phase 27 (Android companion app) follows after that. Phase 14 is partially complete: the Pi's hardware watchdog is deployed and reboot-verified. Read-only-root storage hardening is deferred until persistent storage is moved off the SD root @@ -222,7 +224,7 @@ partition, and clean shutdown still needs delayed-power or ignition-sense hardwa The browser-based phone relay was removed after real-world testing confirmed that mobile browsers cannot reliably use the Pi's WiFi and cellular data simultaneously. A native Android companion is -planned later instead (Phase 26). +planned later instead (Phase 27). The local web UI includes a Settings page for safe runtime configuration: dashcam uploads, uploaded-video retention, cellular APN fallback, optional ntfy delivery, alert thresholds, local @@ -235,9 +237,10 @@ The Pi can also join a configured phone hotspot for outbound internet when no SI including trip synchronization and WiFi dashcam uploads, with automatic recovery to home WiFi or the Pi-hosted local hotspot. -A temporary, removable real-vehicle compatibility test in the 2013 Yaris (Phase 25) precedes the -final low-priority Android phase (Phase 26). Permanent installation is owner-handled and is not a -roadmap phase. Full phase history, verification notes, and current scope live in +The Phase 25 real-vehicle compatibility test has been completed by the owner (road test). The +bugs it surfaced are tracked in [BUGS.md](./BUGS.md) and scheduled for fixing in Phase 26. The +final low-priority Android companion follows in Phase 27. Permanent installation is owner-handled +and is not a roadmap phase. Full phase history, verification notes, and current scope live in [PLAN.md](./PLAN.md). ## Diagnostics & recovery