Commit Graph
67 Commits
Author SHA1 Message Date
Mathieu Moran 42d7f8eb18 fix: clamp max-speed label at edges + move trip location next to time
- placeMaxTick() clamps the label so it stays within the scrubber instead of
  overlapping the time/speed readouts when max speed is near an edge
- give the scrubber row more bottom margin (mb-3) so the tick label clears the
  readout row below
- move the trip location readout directly under the timestamp (left side),
  removing the separate bottom line
2026-08-15 18:14:21 -04:00
Mathieu Moran 0072322bc2 style: timeline max-speed tick as up-arrow + 'Max speed' label
Replace the circle dot on the scrubber with a small up-pointing arrow just
below the line and a 'Max speed' text label.
2026-08-15 18:05:38 -04:00
Mathieu Moran 7d6dd28680 feat: max-speed marker scrubs timeline + timeline tick (FEAT-16)
- Clicking the amber max-speed map marker now jumps the replay to that point
- Add an amber tick on the scrubber at the max-speed position (clickable too)
- Both on Pi and server portal
2026-08-15 18:00:06 -04:00
Mathieu Moran 99035e86ee feat: checkbox batch trip delete on the Pi (local-only)
- Pi history page gets a select checkbox column + 'Delete selected' button
  (mirrors the server UI)
- POST /api/trips/delete batch endpoint
- app_sql.delete_trips_batch() + deleted_trip_markers table so a later trip
  rebuild can't resurrect locally-deleted trips
- Deletion is local-only: raw tracking rows are kept and the remote server
  is never notified (it keeps its archival copy recomputed from uploaded rows)
2026-08-15 16:55:30 -04:00
Mathieu Moran e873db918d Add clear DTC codes button to Pi DTC page (FEAT-15) 2026-08-13 16:40:15 -04:00
Mathieu Moran fa8ae0001a ui: use redacted dashboard screenshots + restore GitHub footer link
- pics/ui.png regenerated from redacted desktop + mobile screenshots
- restore GitHub footer link in Pi + server base.html (accidentally removed)
2026-08-12 23:44:40 -04:00
Mathieu Moran 495e0a99f9 docs: refresh readme status + dashboard screenshots
- Project status -> Phase 27 done, Phase 28 (Android app) in progress
- Added Android companion app to feature list
- Regenerated pics/ui.png (mobile 390px + desktop 1280px dashboards)
2026-08-12 22:58:59 -04:00
Mathieu Moran 7f6d6c3a89 fix: show correct 'reach the Pi' URL per uplink mode + BUG-15
- Settings: when the Pi is on the phone's hotspot (mode phone), show the
  Pi's hotspot IP (http://<ip>) with an LTE-only hint instead of the AP URL
- BUG-15 documents the phone dual-role routing loop (host hotspot + connect
  to AP simultaneously breaks the uplink)
2026-08-12 22:38:31 -04:00
Mathieu Moran 2012370cef ui: stack odometer under speed in replay timeline + GitHub footer link (Pi + server) 2026-08-12 17:24:34 -04:00
Mathieu Moran 0d5aea5947 feat: simulated odometer in trip replay + trip list (continuous across trips)
- Pi route_points: emit per-point odometer (raw OBD value or baseline+prior+within-trip distance)
- Pi get_trip_route: SELECT ODOMETER, compute prior-trips distance + baseline
- Pi list_trips: fallback now starts from baseline (was 0)
- Server get_trip_route: per-point odometer (raw or simulated) with haversine accumulation
- Server list_trips: odo_start/end from baseline + cumulative (was hardcoded None)
- history.js: Odometer line in replay scrubber below speed
- Both history templates: trip-replay-odometer element
2026-08-12 16:59:00 -04:00
Mathieu Moran cfd9d03e81 ui: rework Pi settings page — grouped sections, icons, clearer labels
- Four logical sections: Car & identity, Connectivity, Server & uploads, Alerts
- FontAwesome icons on every card header for visual scanning
- Reordered cards (identity → in-car AP → phone hotspot → server → uploads → alerts)
- settings-section + settings-card styles added via block styles
- Improved helper text (device name, odometer, hotspot password)
- All element IDs preserved — JS behavior unchanged
2026-08-12 16:43:04 -04:00
Mathieu Moran 2cfbe67a86 ui: move Test connection + Sync now buttons to header, left of Save settings
- Header now has Test connection, Sync now, Save settings in a row
- remote-config-message alert moved below header for inline feedback
- Removed buttons from Remote server credentials card
2026-08-12 16:35:09 -04:00
Mathieu Moran db971ab0e3 style: red underline on mobile topbar logo 2026-08-12 05:37:26 -04:00
Mathieu Moran 4a919b55a1 style: dark mobile UI — bottom nav + topbar match sidebar
- Mobile bottom nav: white → dark (#1c1c1e) bg, white icons/text
- Mobile topbar: white → dark bg on small screens, white text/controls
- Mobile logo color: dark → white for dark bg readability
- Desktop topbar remains white (contrasts with dark sidebar)
2026-08-12 05:34:24 -04:00
Mathieu Moran 336815b49c feat: Pi hotspot SSID/password configurable from Settings page
- Settings page: SSID + password fields in In-car access card
- GET /api/hotspot reads current SSID (password never returned)
- POST /api/hotspot updates via nmcli (Hotspot-local profile on wlan0)
- deploy/yaris-hotspot.sudoers for privileged nmcli access
- Password is write-only with placeholder hint
2026-08-12 05:15:55 -04:00
Mathieu Moran 2989f60f9c style: minimalist Material icon buttons (download, upload, delete)
- DashcamScreen: Download + Delete as IconButton with Icons.Filled
- DownloadsScreen: CloudUpload + Delete as IconButton
- No text labels, just clean Material icons
2026-08-12 04:27:51 -04:00
Mathieu Moran 6b47dafdb8 style: yaris-obd lowercase logo 2026-08-12 04:23:42 -04:00
Mathieu Moran d613252155 style: dark sidebar + Racing Sans One YARIS wordmark logo
- Sidebar bg: navy (#1a1a2e) → dark gray (#1c1c1e)
- Logo: replaced fa-car icon + text with styled YARIS wordmark
  using Racing Sans One (free Google Font, OFL licensed)
- Red accent underline (#e63946) on logo
- Applied to both server (server/templates/base.html) and
  Pi (templates/base.html) + mobile topbar
2026-08-12 04:15:51 -04:00
Mathieu Moran 34253b3ffb feat: manual odometer baseline — Settings field computes baseline + trip distance, Dashboard shows (manual) label 2026-08-11 18:51:11 -04:00
Mathieu Moran 5713417f4f Server: restore checkbox + batch-delete. Conditional ID (server only) and checkbox via data-show-id/data-batch-delete-url. 2026-08-11 15:11:12 -04:00
Mathieu Moran 23ac6c218b feat: add trip ID column (#18517) to history table on Pi and server 2026-08-11 14:58:25 -04:00
Mathieu Moran 89bbc4fdb8 fix(phase26): skip netwatch AP scan when clients connected (BUG-01) 2026-08-11 03:11:13 -04:00
Mathieu Moran c5c478bef6 fix(phase26): add Pi trip deletion (BUG-08) 2026-08-11 02:07:59 -04:00
Mathieu MoranandCopilot b815e0aaaa Swap dashboard map and overview
Co-authored-by: Copilot <[email protected]>
2026-08-10 18:43:01 -04:00
Mathieu MoranandCopilot 8907c51016 Add status page quick actions
Co-authored-by: Copilot <[email protected]>
2026-08-10 18:40:22 -04:00
Mathieu MoranandCopilot 5406935bf5 Add Pi status page
Co-authored-by: Copilot <[email protected]>
2026-08-10 18:37:26 -04:00
Mathieu MoranandCopilot a7302229d1 Tighten Pi dashboard layout
Co-authored-by: Copilot <[email protected]>
2026-08-10 18:25:30 -04:00
Mathieu MoranandCopilot be40bbc15f feat: add GPS status endpoint and dashboard indicator
- add /api/gps/status for thread/fix-age visibility
- surface GPS status in Pi health and live GPS cards
- add tests for app_gps status snapshots

Co-authored-by: Copilot <[email protected]>
2026-08-10 18:18:14 -04:00
Mathieu MoranandCopilot ba682fbf3a feat: add multi-device provisioning and local remote-config UI
- add multi-device portal device management, key rotation, and sync request APIs
- add Pi settings UI for remote server URL, device name, and API key
- add local test-connection and sync-now actions
- make upload and config sync reuse dynamic shared credentials
- add Phase 25.5c migration and docs updates

Co-authored-by: Copilot <[email protected]>
2026-08-10 18:02:09 -04:00
Mathieu MoranandCopilot d7b9bb634f feat: add device config settings UI with optional server sync
- Add app_device_config.py module for managing device configuration (owner_name, car_model, avatar_path, device_name)
- Add sync_enabled flag to control whether Pi syncs config from server
- When sync is enabled, device config fields are read-only (server is source of truth)
- When sync is disabled, user can edit device config via Settings page
- Add /api/device-config endpoint (GET to retrieve, POST to update)
- Add Device identity section to settings.html with form fields for all config values
- Update settings.js to load/save device config with sync toggle
- Gracefully handles both config file (at startup) and database (live updates via settings UI)
- All 63 tests passing

Phase 25.5: Offline-first device config with eventual consistency. Config loads from JSON at startup (no network needed), can be edited via settings if not syncing, and will sync from server on next connectivity when Phase 25.5a server endpoints are implemented.

Co-authored-by: Copilot <[email protected]>
2026-08-10 16:41:45 -04:00
Mathieu MoranandCopilot c65a635906 implement: Phase 25.5 device config from JSON file
- Create config/device.json with owner_name, car_model, device_name, avatar_path
- Update app_account.py to load owner_name and avatar_path from config
- Update app_car.py to load car_model and device_name from config
- Update base.html template to use avatar_path from config instead of hardcoded
- Add graceful fallback to hardcoded defaults if config file missing
- Document in deploy/readme.md and readme.md how to customize device identity
- Update PLAN.md Phase 25.5 to reflect current implementation and future server sync

Benefits:
- No code edits needed to customize Pi (edit JSON file only)
- Offline-first: all values loaded from local file at startup
- Connection-driven sync planned for Phase 25.5a (sync when internet available, not on timer)
- Server becomes source of truth after Phase 25.5a implementation

All 63 tests passing. Database filename still based on owner_name, with migration warning in docs.

Co-authored-by: Copilot <[email protected]>
2026-08-10 16:31:59 -04:00
Mathieu MoranandCopilot c287ab67a3 fix: map zoom limits configurable per-deployment via data attributes
Pi offline tiles only cover zoom 8-15; OSM live tiles support 0-19.
history.js now reads data-min-zoom/data-max-zoom from the #history-map div
instead of hardcoding 3/19. Pi template caps to 8-15 (prevents blank tiles
at extreme zooms), server template allows full 3-19 OSM range.

Co-authored-by: Copilot <[email protected]>
2026-08-10 05:42:04 -04:00
Mathieu MoranandCopilot e96c6a16bb fix(network): stable phone hotspot IP via dhcp-client-id=yaris-obd
- Phone DHCP caches by client-id so Pi always gets same lease
- Remove dashboard phone-hotspot banner (didn't work)

Co-authored-by: Copilot <[email protected]>
2026-08-10 03:11:41 -04:00
Mathieu MoranandCopilot a6c6cddf30 feat(dashboard): show Pi IP banner when connected to phone hotspot
- Banner appears on dashboard only when uplink mode is 'phone'
- Shows the Pi's current IP so you can reach it from your phone's browser
- Polls every 15s, hides automatically when not on phone hotspot

Co-authored-by: Copilot <[email protected]>
2026-08-10 03:06:39 -04:00
Mathieu MoranandCopilot 548808fd83 feat(history): show reverse-geocoded location during trip scrubbing
- Location name (road + city) appears below time/speed in the timeline panel
- Debounced 600ms so dragging the scrubber doesn't spam Nominatim
- Deduped by ~3 decimal lat/lon so stationary replay doesn't re-fetch
- Cleared when a new trip is loaded

Co-authored-by: Copilot <[email protected]>
2026-08-10 02:45:41 -04:00
Mathieu MoranandCopilot f1145a4dbb feat(map): reverse geocode location + recenter button on dashboard and history
- Dashboard: recenter button in GPS card header (hidden until first fix)
- Dashboard: estimated location name under lat/lon via Nominatim reverse geocode (throttled 30s)
- History: recenter button fits map back to trip bounds
- Both buttons use crosshairs icon, hidden until data is available

Co-authored-by: Copilot <[email protected]>
2026-08-10 02:43:23 -04:00
Mathieu MoranandCopilot f27e2f2d4b ui: remove imperial units, hide Replay button on mobile
- formatDistance/formatSpeed: km/km/h only, no mi/mph
- Replay button hidden on mobile (d-none d-sm-table-cell)
- Action column header hidden on mobile to match
- data_table macro supports optional 'class' on column headers

Co-authored-by: Copilot <[email protected]>
2026-08-10 02:38:50 -04:00
Mathieu MoranandCopilot afce229310 feat: odometer in trips/overview, trips upload toggle, fix video count
- OBD odometer now logged to tracking rows on every GPS snapshot
- trips table: START_ODOMETER/END_ODOMETER columns (migration)
- build_trip_summaries: picks odometer from first/last tracking row
- list_trips: uses real OBD odo, falls back to cumulative distance
- overview stats: odometer_km (max seen from OBD), video_count fixed
- history page: Odometer column shows start→end km per trip
- app_upload: TRIPS_UPLOAD_SETTING_KEY, is_trips_upload_enabled()
- _upload_tracking_batch: skips when trips upload is off
- settings: separate 'Upload trips & GPS' toggle from dashcam toggle

Co-authored-by: Copilot <[email protected]>
2026-08-10 02:07:31 -04:00
Mathieu MoranandCopilot 5b2854fbec fix(dashcam): use style.display instead of hidden attr (d-flex overrides hidden)
Bootstrap d-flex sets display:flex !important which beats the HTML hidden
attribute. Switch to style.display='none'/'flex' for both status bars.

Co-authored-by: Copilot <[email protected]>
2026-08-10 00:51:27 -04:00
Mathieu MoranandCopilot ba760a04d6 fix(dashcam): proper mobile row reflow + import status at top with ETA
- yaris.css: use .dash-row class on all rows; only td:first-child and
  .dash-actions-td visible on mobile (<576px); buttons never overflow
- dash.js: add dash-row class + dash-actions-td wrapper div to dashcam
  file rows; import status moved to card footer at top with spinner + ETA
- local-videos.js: add dash-row class to video rows
- dash.html: import status bar (spinner + ETA + result) in device card
  at top; removed old footer import status from files card

Co-authored-by: Copilot <[email protected]>
2026-08-10 00:46:05 -04:00
Mathieu MoranandCopilot 01704d5429 feat(dashcam): mobile layout fix + optional hw-encode conversion on import
- yaris.css: on mobile (<576px) hide file/size/date/upload cols, show
  filename inside thumb cell, icon-only buttons, dash-actions-td nowrap
- local-videos.js: filename in thumb cell for mobile; Converting badge with
  spinner; auto-refresh every 10s while any file is converting
- app_video.py: CONVERT_SETTING, is_convert_enabled(), queue_convert(),
  _convert_bg() — h264_v4l2m2m + aac faststart, deletes original on success
- app_dash.py: call queue_convert() after each successful copy on import
- app_settings.py: expose video_convert_enabled in get/save settings
- settings.html: toggle for 'Convert imported videos for web playback'

Co-authored-by: Copilot <[email protected]>
2026-08-10 00:30:59 -04:00
Mathieu MoranandCopilot 5d9b2f6556 feat(dashboard): 3-col layout with Overview stats, speed chart fixes
- base.html: fix notification badge positioning (inline style, no overflow
  clip); remove py-4 from main; update footer text
- index.html: split bottom row into 3 cols (GPS / Overview / Speed);
  Overview card with 6 live stats from /api/stats; speed chart auto-expands
  on desktop; shown.bs.collapse triggers speedChart.resize()

Co-authored-by: Copilot <[email protected]>
2026-08-10 00:13:23 -04:00
Mathieu MoranandCopilot 600fd41353 fix(dashcam): range-request video streaming, modal player, async thumbnails
- app.py: replace send_file with manual Range-aware chunked generator;
  returns 206 on partial requests so browsers can seek/buffer properly.
  Thumbnail route returns 202 while ffmpeg is generating.
- app_video.py: thumbnail generation moved to background gevent greenlet
  (_generate_thumbnail_bg). get_thumbnail_path returns immediately with
  RuntimeError('generating') if not cached; ffmpeg only ever runs once
  per video (result cached in dash/thumbnails/).
- dash.html: replaced bottom card player with Bootstrap modal (modal-xl,
  centered, dark bg) — video pops up in place regardless of scroll position.
- local-videos.js: rewritten to use Bootstrap modal; thumbnail loader
  polls with fetch() and retries on 202 every 2s (up to 15x) instead of
  setting img.src directly (which can't detect 202).

Co-authored-by: Copilot <[email protected]>
2026-08-10 00:01:49 -04:00
Mathieu MoranandCopilot e2f7fa88df Speed history: rework chart and add live stats
- Replace 8-point scatter chart with proper 60-point line chart
  - Blue gradient fill (rgba 35%→2%), tension 0.4 smooth curve
  - No legend (obvious), no X axis grid, soft Y axis gridlines
  - Y axis auto-scales: max(60, sessionMax*1.2) rounded to 10s
  - Ticks: '0 km/h' labels on Y, time strings on X (max 6)
  - chart.update('none') for live updates (no animation stutter)
- Speed history card header now shows current speed + session max
  even when the graph is collapsed
- Footer bar inside expanded graph: session avg, point count, last reading time
- makeGradient() refreshed on every update in case canvas was resized
- obd_rpm now appends ' rpm' to the displayed value

Co-authored-by: Copilot <[email protected]>
2026-08-09 23:14:32 -04:00
Mathieu MoranandCopilot beddfec8a5 Phase 23 UX polish: compact layouts, collapsibles, test trip
Dashboard:
- OBD stat cards more compact (py-2, h6 health values, 'OBD' label fits)
- obd-val class prevents Disconnected wrapping
- Speed graph collapsed by default with toggle chevron button
- GPS map + coordinates merged into single card with footer coords
- Pi health rows use h6 (less tall), alert py-2

Dashcam:
- Device status is now a compact single-line bar
- Files on dashcam section is collapsible (hidden by default)
- Import status moved into the dashcam files card footer
- Imported videos on Pi moved to top, open by default
- Column headers trimmed (Select→empty, Actions→empty, Preview→empty)

Trip history:
- col-12 on mobile so list stacks above the map
- Shorter column labels (Distance→km, Duration→Time, Max speed→Max)
- history-map height reduced for mobile (22rem on small screens)

Settings:
- Cellular + ntfy merged into one collapsible card
- Alert thresholds collapsible (advanced)
- Phone hotspot instructions shortened
- Upload retention uses inline row layout (compact)
- All cards use shadow-sm, smaller headers

CSS:
- obd-val: word-break + smaller font for OBD status values
- collapse-chevron: smooth rotation transition
- #map height 18rem (was 20rem)
- history-map 32rem desktop / 22rem mobile (was 36rem)

Co-authored-by: Copilot <[email protected]>
2026-08-09 23:10:58 -04:00
Mathieu MoranandCopilot 7edea446c5 Phase 23: UI redesign — responsive mobile + desktop layout
- Replace SB Admin 2 sidebar with a clean fixed sidebar (desktop)
  and a sticky bottom tab navigation (mobile, ≤767px)
- Sidebar collapses to icon-only mode with state persisted in localStorage
- Logo is a functional home link on all viewports
- Mobile: full-width content, bottom nav replaces sidebar
- Dashboard: 6 OBD stat cards (status, speed, RPM, coolant, throttle, fuel)
  wired to live socket events; removed all placeholder buttons/dropdowns
- GPS info section cleaned up (lat/lon display instead of X/Y paragraphs)
- DTC page: live /api/dtc wiring — MIL indicator + DTC table populated from API
- New /api/dtc route added to app.py (mil + codes)
- yaris.js: added obd_coolant_temp / obd_fuel_level / obd_throttle listeners
- yaris.css: full rewrite — layout variables, sidebar, bottom nav, OBD cards,
  border-start utilities, mobile padding for bottom nav

Co-authored-by: Copilot <[email protected]>
2026-08-09 22:57:12 -04:00
Mathieu MoranandCopilot cdb032b888 Add phone hotspot uplink
Prefer a configured phone hotspot for outbound synchronization, preserve secure write-only credentials, and recover through home WiFi or the local Pi hotspot.

Co-authored-by: Copilot <[email protected]>
2026-08-09 22:48:11 -04:00
Mathieu MoranandCopilot 3a6f12ba9d Add local settings management
Add cellular-first ntfy delivery with WiFi fallback and safe SIM868 HTTP header framing.

Co-authored-by: Copilot <[email protected]>
2026-08-09 21:26:15 -04:00
Mathieu MoranandCopilot 96332adab6 Add offline and ntfy alerts
Co-authored-by: Copilot <[email protected]>
2026-08-09 20:28:42 -04:00
Mathieu MoranandCopilot 8b664667e5 Add Raspberry Pi health monitoring
Co-authored-by: Copilot <[email protected]>
2026-08-09 19:57:07 -04:00