- update plan with live portal route deployment status
- document fixed Pi sync blockers and successful round-trip test
- refresh passing test count after runtime sync coverage additions
Co-authored-by: Copilot <[email protected]>
- load server sync creds from db/upload_creds.env like uploads do
- fall back from YARIS_DEVICE_KEY to existing YARIS_API_KEY
- document shared credential flow for server-synced identity
- add test coverage for sync credential fallback
Co-authored-by: Copilot <[email protected]>
- use app_network status for device sync connectivity checks
- mount migrate_phase25_5a.sql in server docker compose
- document manual server upgrade migration steps
- record verified Pi and unraid SSH access details in PLAN
Co-authored-by: Copilot <[email protected]>
- Created app_device_sync.py: background sync thread with connectivity-driven scheduling (5min online, 60sec backoff when offline)
- Server /api/device-config endpoints: GET for Pi device auth, POST for admin user auth
- Database migration adds config_version, owner_name, car_model, device_name, avatar_path to devices table
- Pi syncs config from server on network availability; offline-first design (loads from local JSON at startup)
- Settings UI fields read-only when server sync enabled
All 63 tests passing. Ready for testing with actual server connection.
Co-authored-by: Copilot <[email protected]>
- Settings UI now implemented for device config editing
- Sync toggle blocks field edits when enabled
- All behaviors tested and verified on Pi
- Phase 25.5a will add server-side config endpoints and connection-driven sync
Co-authored-by: Copilot <[email protected]>
- 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]>
Plan for replacing hardcoded user/car/avatar with managed server-synced configuration, enabling multi-device and zero-code-edit deployment scenarios.
Co-authored-by: Copilot <[email protected]>
Counterfeit ELM327 chips (common in cheap PL2303 USB adapters) often report
bad/zero voltage even when the OBD connection is working. python-obd's
check_voltage=True default rejects these. Add OBD_SKIP_VOLTAGE_CHECK=1 env
var to pass check_voltage=False to obd.OBD(), documented in yaris-obd.service.
Also document Phase 24.6 Yaris 2013 compatibility analysis in PLAN.md.
Co-authored-by: Copilot <[email protected]>
- 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]>
Phase 23 section updated with full list of changes from all polish passes:
Overview stats card, speed chart rework, mobile dashcam table fixes,
trip history mobile layout, notification badge fix, footer text.
README project status updated to reflect Phases 1-23 complete.
Co-authored-by: Copilot <[email protected]>
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]>
Recorded Phase 12's deployment step (Pi restart + unraid server
docker compose build/up since server/app.py's CORS removal is baked
into the image at build time - a plain restart wouldn't pick it up)
and its verification (both confirmed on real infrastructure: Pi's
/dash returns HTTP 200 with no relay text, server's /health has no
Access-Control-* headers anymore).
Added a handoff note for whoever picks this up next: Phase 17 (OBD
hardening) was the next phase in progress, but no code was written
yet - only read app_events.py/app_gps.py for context and started
(but didn't finish, due to a tool permission interruption) installing
the python-obd package locally to check its actual API surface
before writing the DTC/protocol/diagnostics code. Reset that todo
back to pending to reflect no actual progress was made. Phases 13
and 14 are equally ready to start (no blocking deps) if a different
starting point makes more sense.
Co-authored-by: Copilot <[email protected]>
Removes the phone-relay feature entirely per the Phase 11 finding
that it hit a fundamental phone-OS limitation (a browser page can't
route WiFi and cellular traffic simultaneously, no code fix possible)
- see PLAN.md for the full test writeup.
- app.py: dropped /api/dash/pending, /api/dash/file/<path>,
/api/dash/relay/config, /api/dash/relay/heartbeat,
/api/dash/relay/stop, /api/dash/relay/mark_uploaded routes and
their now-unused imports (os, send_file, abort, safe_join).
- modules/app_upload.py: dropped list_pending_dashcam_files(),
relay_heartbeat()/relay_stop()/is_relay_active(),
RELAY_LEASE_SECONDS/_relay_lease_until, and the relay-lease check
inside _upload_dashcam_files()/get_status(). Kept the chunked
upload protocol, dashcam_hash_cache/_hash_dashcam_file() (still
used by the Pi's own background uploader), and DASHCAM_CHUNK_SIZE -
none of that was relay-specific.
- templates/dash.html: removed the 'Relay via phone' card.
- static/js/dash.js: removed all relay JS (relayOneFile,
fetchChunkWithRetry, uploadChunkWithRetry, heartbeat timers,
pending-file list rendering).
- server/app.py: removed the CORS after_request hook, added solely
for the phone's cross-origin browser calls (the Pi's own Python
requests-based client was never subject to CORS).
- readme.md: dropped the phone-relay feature bullet, updated the
project-status blurb to explain the removal + point at the planned
native Android app as the real fix for that use case.
- PLAN.md: marked Phase 12 done with a verification writeup.
Verified: py_compile on all touched Python files, node --check on
dash.js, grepped all touched files for any leftover relay/RELAY
reference (none), and smoke-tested by importing app.py + hitting it
with Flask's test client - app starts cleanly, every relay route is
gone from url_map, and both / and /dash still render HTTP 200 with
zero 'relay' occurrences in /dash's HTML.
Co-authored-by: Copilot <[email protected]>
Reordered/renumbered the roadmap based on dependency analysis:
- Phase 12 (remove relay) stays first - pure cleanup, no deps.
- New Phase 13: power-loss resilience + hardware watchdog - OS-level,
independent, should land before the Pi lives in the car full-time
(cars cut power abruptly at every key-off, a real SD-corruption risk
nothing in the project currently addresses).
- New Phase 14: UI design-system foundation - pulls forward a small
slice of the old end-of-roadmap redesign (shared layout + reusable
list/table component) so the dashcam/video browsers, trip history,
and settings pages are all built on it once instead of being built
in the old template and then rebuilt during the redesign later.
- Phases 15/16 (dashcam + local video browsers) now explicitly build
on Phase 14's foundation. Folded two more QOL ideas directly into
Phase 16: ffmpeg thumbnails per video, and an optional
upload-confirmed local retention/auto-cleanup policy.
- Phase 17 (OBD hardening) explicitly marked independent/parallel-
frins to other phases - backend-only work, no UI dependency.
- New Phase 18: trip history + map replay (trips table + GPS-gap
boundary detection + list/replay UI reusing the offline Leaflet map).
- New Phase 19: Pi health monitoring card (CPU temp/disk/uptime/RAM).
- New Phase 20: alerts/notifications via a simple outbound webhook
(ntfy.sh/Telegram) for DTC-on, storage full, backlog growing,
overheating, lost GPS fix.
- New Phase 21: consolidated Settings page (upload toggle, cellular
APN, retention policy, alert config) - reduces routine SSH-editing.
- Phase 22: renamed 'Finish web UI redesign' - now scoped as the
remaining cleanup after Phase 14's foundation + all functional
phases land, rather than one big redesign at the very end.
- Phase 23: native Android app, unchanged content, still last/low
priority per explicit user instruction.
Updated the session's todo tracking table to match the new phase
IDs/order and added todo_deps reflecting the same dependency chain.
Co-authored-by: Copilot <[email protected]>
Formatting-only pass, no information changed:
- Added missing checkmarks to Phase 7 and Phase 9 headers (were plain
'DONE' text while every other completed phase uses '✅ DONE').
- Added a status icon to the un-numbered SIM868 cellular fallback
section ('⚠️ built, UNTESTED').
- Added a consistent '🚧 PLANNED' icon to Phases 12-17, which had no
status icon at all.
- Fixed a stale cross-reference in the Phase 6 update ('see Phase 9
update below' -> 'see Phase 11 update below' - the phone-relay
content it points to has always lived under Phase 11).
Co-authored-by: Copilot <[email protected]>
Phase 16: complete web UI redesign - the current template is full of
never-replaced placeholder cruft (stub buttons, empty /dtc page); do
one real design pass once the functional phases land rather than
keep bolting onto the old admin-template style.
Phase 17: native Android companion app - the real fix for the
phone-relay goal that a web page could never deliver (true
simultaneous WiFi-to-Pi + cellular-to-server via
bindProcessToNetwork), plus a trip/location info view. Explicitly
deprioritized to the end of the roadmap per user - not urgent.
Also expanded Phase 15 (OBD hardening) scope to pull richer dashboard
data (coolant temp, fuel level, throttle, DTC/MIL status) alongside
speed/RPM, noting odometer/mileage support is not guaranteed on this
vehicle/year and needs real-car confirmation.
Co-authored-by: Copilot <[email protected]>
Retested the hotspot+cellular phone-relay scenario more rigorously
(netwatch explicitly disabled during tests so it wouldn't yank the Pi
back to home WiFi mid-test - an earlier failed run turned out to be
caused by that, not a phone issue). Confirmed with WiFi fully off
(pure cellular) that requests to the public server still failed while
associated with the Pi's hotspot, and that this is a fundamental
OS-level 'single default network for the whole device' limitation -
not something a web page's JS can work around, only a native app could
(bindProcessToNetwork). Documented the decision to remove the feature.
Added Phase 12 (remove phone-relay), Phase 13 (dashcam USB file
browser: list+delete), Phase 14 (local imported-video browser +
HTML5 player), Phase 15 (OBD code hardening ahead of first real
car test - background reconnect loop, exception handling, protocol
override, better diagnostics).
Co-authored-by: Copilot <[email protected]>
Live-tested the away-from-home hotspot+cellular relay scenario. Found the
netwatch reconnect bug (documented in Phase 6 update) during this test.
Confirmed the relay architecture itself needs no code changes - the
TypeError: Failed to fetch was a phone-OS network-switching behavior
(won't route internet traffic over cellular while connected to a
no-internet WiFi), not a CORS/code issue - ruled out via a plain page
navigation test. Testing this fully requires being genuinely away from
home or manually forcing cellular use on the phone.
Co-authored-by: Copilot <[email protected]>
Root-caused a "GPS not working" report to the SIM868 module chip being
fully powered off (the HAT's 5V rail can be live while the chip itself
stays off until PWRKEY is triggered) - confirmed by getting zero AT
response at any baud rate while the app's GPS thread had the serial
port open normally.
Discovered this specific HAT revision has the "P4" GPIO power-on mod
wire installed (Waveshare FAQ / GSM_PWRKEY.rar script), letting PWRKEY
be triggered via physical pin 7 (BCM GPIO4) instead of a manual button
press. Verified live: pulsing it low for 4s then high brought the
module from zero AT response to responding immediately.
modules/app_gps.py: added _module_responds()/_pulse_pwrkey()/
_ensure_module_powered(), wired into _poll_loop() before the existing
GNSS power-on check. Checks AT first and only pulses PWRKEY if the
module isn't already responding, since PWRKEY is a toggle (pulsing an
already-on module would turn it back off).
Also fixed a related logging gap found while debugging: print()
diagnostics from app_gps.py were invisible in yaris-obd.log for
months because Python fully-buffers stdout when it isn't a TTY.
deploy/yaris-obd.service now sets PYTHONUNBUFFERED=1.
requirements.txt: added RPi.GPIO.
PLAN.md: documented both findings and the Pi deploy gotchas (systemd
unit file changes need a manual copy + daemon-reload; requirements.txt
changes need a manual venv pip install - neither is picked up by a
plain git pull + restart).
Co-authored-by: Copilot <[email protected]>
Deployed and tested the phone-relay feature end-to-end for real:
found and fixed a deploy gap (CORS fix wasn't rebuilt into the actual
remote server's Docker image, only pulled on the Pi - surfaced as a
generic "TypeError: Failed to fetch" in the browser). After fixing,
measured real throughput from server-side chunk timestamps: ~1.11MB/s
via phone relay (home WiFi) vs ~9-10Mbit/s for the Pi's own direct
upload - statistically the same. Confirms the relay provides no speed
benefit when the phone is on the same home WiFi as the Pi, since the
download-to-phone leg pays the same congested-radio cost either way.
Documented this finding plus a follow-up idea (per-clip browse/select
upload from the phone, not yet designed).
Root-caused the slow-upload complaint to the Pi's own congested 2.4GHz
WiFi radio (confirmed via iperf3 - same degraded throughput even on
pure local LAN traffic, ruling out Cloudflare/ISP). Since the Pi 3 B
has no 5GHz radio, add a way to bypass it for the internet-bound leg:
a phone opens /dash and manually relays pending dashcam files straight
to the remote server over its own network, reusing the exact same
chunked upload protocol the Pi's client already uses.
- server/app.py: add CORS headers (after_request) so the phone's
browser can call the remote server cross-origin from a page served
by the Pi.
- app.py: new endpoints - GET /api/dash/pending (list not-yet-uploaded
files), GET /api/dash/file/<path> (Range-request-capable download,
path-traversal safe), GET /api/dash/relay/config (hands the phone
the device credentials), POST /api/dash/relay/heartbeat|stop (lease-
based pause of the Pi's own background uploader, self-heals if the
phone's tab closes uncleanly), POST /api/dash/relay/mark_uploaded.
- modules/app_upload.py: list_pending_dashcam_files(), relay lease
helpers, _upload_dashcam_files() now pauses while a relay lease is
active.
- modules/app_sql.py: new dashcam_hash_cache table so a file's sha256
is only computed once (keyed by path+size+mtime) instead of being
recomputed on every loop iteration/pending-list call - benefits the
existing background uploader too.
- templates/dash.html / static/js/dash.js: new "Relay via phone" card
- per-file and "relay all" buttons (manual trigger only, per user
preference), downloads+uploads one 40MB slice at a time so the
phone never holds a whole file in memory, retries chunks up to 3x.
- PLAN.md/readme.md/server/README.md updated (Phase 11).
Tested via a full local end-to-end simulation driving the real Pi and
server Flask apps side by side (Postgres mocked only at the db module
boundary - all HTTP/chunking/auth/CORS logic is real): verified Range
downloads (206), byte-for-byte reassembly via SHA256, path-traversal
rejection, and the relay lease correctly pausing/resuming the
background uploader. Not yet tested against a real phone/live network.
- PLAN.md: mark Phase 8 (dashcam retrieval) verified on real hardware, add
Phase 10 documenting the OOM/multipart and Cloudflare body-size fixes plus
the chunked/resumable upload redesign, both verified end-to-end against
real dashcam footage. Update architecture decision #3 (Mongo -> Postgres
supersession), add unraid/Pi deploy notes and memory-budget gotcha.
- readme.md: refresh feature list (remote upload, chunked dashcam uploads,
toggle) and project status (all 10 phases done, only cellular fallback
untested).
- server/README.md: document the new chunked upload endpoints and the
Cloudflare body-size-limit rationale behind them.