docs: update PLAN.md phase 23.5, README features/hardware/status, new screenshots

- PLAN.md: Phase 23.5 documents all work from this session
- README: hardware table adds T3U, features add geocoding/offline maps/T3U, status updated
- pics/ui.png: desktop + mobile side-by-side screenshot (updated)

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-10 03:43:09 -04:00
co-authored by Copilot
parent 58faded602
commit 51c6be3a94
2 changed files with 74 additions and 9 deletions
+47
View File
@@ -1194,6 +1194,53 @@ including two UX polish passes and multiple bug-fix rounds.
- Synthetic test trip in DB: 50 points, Old Port → Plateau Montreal, 3 km, 8 min, 43.5 km/h max.
- All 63 tests pass. Verified on Pi at 390×844 (mobile) and 1280×800 (desktop).
### Phase 23.5: UI polish, dashcam improvements, odometer, WiFi upgrade — ✅ DONE
**Completed 2026-08-10.** A focused multi-session polish and hardware upgrade pass on top of Phase 23.
**Dashcam & video:**
- Async dashcam import — import now fires in a background thread, returns `{status:"started"}` immediately, and the UI polls `/api/dash/import/status` every 3 s. Eliminates mobile timeout and `_device_lock` blocking all routes during copy.
- Per-file Convert button on MOV/non-MP4 files. `/api/local-video/convert` POST with `force=True` bypasses the auto-convert toggle.
- Real ffmpeg progress via `-progress pipe:1` — reads `out_time_ms` lines in a thread, computes `pct = out_time_s / duration_s * 100`. Old `elapsed/duration` estimate was wrong for RPi3 (encodes slower than realtime).
- Bitrate set to `-b:v 4M -b:a 128k` (~100 MB per 3-min clip); previous default was unusably small.
- `.converting.mp4` temp files excluded from file list and upload queue.
- Thumbnail patching during conversion — `refreshConvertingOnly()` updates badge text in-place without a full re-render; full render only when file count changes. Fixes thumbnail-reload flicker every 10 s.
- Mobile converting badge: spinner + % shown under thumbnail on mobile (`dash-thumb-meta`, `dash-thumb-converting`).
- Mobile checkbox column now visible in dashcam file list.
- Download button on Pi video files (`/api/local-video/file?download=1`, `as_attachment=True`).
**Odometer & trips:**
- `_log_loop` passes `app_obd.odometer` to `insert_tracking()` — OBD odometer now stored in every tracking row.
- `START_ODOMETER` / `END_ODOMETER` columns added to trips table (auto-migrated).
- `build_trip_summaries()` reads odometer from first/last tracking row of each trip; `list_trips()` falls back to cumulative distance sum for legacy trips with NULL odometer.
- Overview dashboard: `odometer_km` (MAX from tracking) and `video_count` now included in `/api/stats`.
- Trip history table: new "Odometer" column showing `start → end km`.
**Settings:**
- Separate upload toggles: "Upload trips & GPS logs" and "Upload dashcam videos (WiFi only)" are now independent switches. `TRIPS_UPLOAD_SETTING_KEY` added to `app_upload.py`.
**Map & location:**
- Recenter (⊕) button on dashboard GPS card and history route map.
- Offline reverse geocoding via `reverse_geocoder` Python library (~20 MB KD-tree, no internet needed). Exposed as `/api/geocode?lat=&lon=` — browser never calls any external service.
- When internet is available (phone hotspot), `/api/geocode` tries Nominatim first for street-level accuracy, falls back to `reverse_geocoder` for city/region. Results cached with `functools.lru_cache(512)` keyed at 4-decimal precision (~11 m).
- Dashboard GPS card footer: location name shown below lat/lon, updated on first fix and after moving >50 m.
- Trip history scrubber: location name shown in timeline panel, debounced 600 ms while scrubbing.
- GPS coords parsed as `float` before `toFixed()` — was crashing silently on string input from socket.
**Trip history UX:**
- Imperial units removed from `formatDistance` and `formatSpeed` (km / km/h only).
- Replay button hidden on mobile (`d-none d-sm-table-cell`); tapping anywhere on the trip row triggers replay instead (`data-trip-id` on `<tr>`, `cursor: pointer`).
- `data_table` macro supports optional `class` on column headers.
**WiFi upgrade — TP-Link Archer T3U (RTL8812BU):**
- RTL8812BU DKMS driver built and installed on Pi (`morrownr/88x2bu-20210702`, kernel 6.12.96+rpt-rpi-v8).
- `INTERFACE = "wlan1"` in `yaris_uplink.py`; `install_netwatch.sh` rebinds home-wifi, Hotspot, phone-hotspot to wlan1.
- `resolve_interface()` checks `/sys/class/net/wlan1` at startup — falls back to `wlan0` automatically if dongle is absent or driver fails. `INTERFACE` is module-level so all functions use the correct iface.
- `restore_fallback()` extended: if wlan1 primary fails, also tries `home-wifi-fb` and Hotspot on wlan0.
- `install_netwatch.sh` creates `home-wifi-fb` profile on wlan0 with `autoconnect=no` and lower priority — NM uses it only when explicitly activated by `restore_fallback()`.
- `dhcp-client-id=yaris-obd` in phone-hotspot keyfile — phone DHCP assigns a consistent lease by client-id, giving the Pi a stable IP on the phone hotspot network.
- Status JSON now includes `interface` field for diagnostics.
- SSH alias updated to new wlan1 IP (192.168.50.213).
### Phase 24: Remote trip + dashcam portal with shared web UI — 🚧 PLANNED
**Added 2026-08-09; intentionally scheduled after Phase 23.** Phase 23 first establishes the final
visual language and complete in-car interface. Building the remote portal afterward avoids