Commit Graph
107 Commits
Author SHA1 Message Date
Mathieu Moran e80c60c9f1 Document real-hardware phone-relay test results in PLAN.md
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).
2026-08-09 01:13:09 -04:00
Mathieu Moran 0d67a21ae1 Add phone-relay dashcam upload to bypass the Pi's slow WiFi
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.
2026-08-09 00:15:27 -04:00
Mathieu Moran 8c33c669a5 Document Phase 8/10 real-hardware validation in PLAN.md and refresh READMEs
- 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.
2026-08-08 23:33:01 -04:00
Mathieu MoranandCopilot 6d61b70a06 Add SIM868 cellular fallback for tracking uploads (untested, no SIM card)
modules/app_cellular.py: uses the SIM868's built-in AT-command HTTP(S)
client (AT+HTTPINIT/HTTPPARA/HTTPACTION/HTTPREAD) instead of a real
ppp0 interface, since the module's GNSS (polled continuously by
app_gps.py) and its GSM/GPRS radio share the same physical UART
(/dev/serial0) - a pppd/chat dial-up would take over that port
entirely and starve GNSS polling. Staying in AT-command mode lets
cellular HTTP calls interleave safely through the same serial lock.

Only carries small JSON tracking batches, never dashcam video -
cellular is far too slow/limited for that, and the modem's HTTP AT
interface has too small an internal buffer anyway. Dashcam uploads
remain WiFi/Ethernet-only, unchanged.

modules/app_upload.py: tracking-batch upload always tries WiFi/
Ethernet first; only on a connection-level failure (not an HTTP error
status, which means the server was reached) does it retry over
cellular. Exposes last_network_path/cellular_fallback_configured in
/api/upload/status; UI shows which path the last batch used.

Feature-flagged off by default via new YARIS_CELLULAR_ENABLED/
YARIS_CELLULAR_APN/_APN_USER/_APN_PASS keys in db/upload_creds.env
(all blank by default) - has zero effect on the existing WiFi upload
path unless explicitly configured. Regression-tested against the real
deployed server that normal WiFi uploads are unaffected while
cellular stays unconfigured.

*** UNTESTED against real cellular hardware - no SIM card was
*** available. See docstrings in app_cellular.py and PLAN.md for
*** exactly what needs validation once a SIM card is available.

Co-authored-by: Copilot <[email protected]>
2026-08-08 20:34:53 -04:00
Mathieu MoranandCopilot cea62d8c10 Mark Phase 9 (remote server) as DONE in PLAN.md
Reflects the completed deployment: server running on unraid, exposed
at https://yaris.ceaf.dev via Cloudflare Tunnel, Pi-side upload client
live and backlog-drain tuned.

Co-authored-by: Copilot <[email protected]>
2026-08-08 20:21:22 -04:00
Mathieu MoranandCopilot 9bdf5bad2c Phase 9: scaffold remote server (Flask + Postgres, docker-compose for unraid)
- server/sql/init.sql: devices/tracking_points/dashcam_files schema
- server/modules/db.py: psycopg3 pool + query helpers
- server/modules/auth.py: X-Device-Name/X-Api-Key header auth
- server/app.py: /health, /api/v1/tracking/batch, /api/v1/dashcam/upload
- server/Dockerfile + docker-compose.yml: api (gunicorn) + postgres services
- server/scripts/create_device.py: one-time device/API-key registration
- server/README.md: unraid deployment + Cloudflare Tunnel exposure docs
- PLAN.md: Phase 9 marked in progress with full build notes

Co-authored-by: Copilot <[email protected]>
2026-08-08 19:50:52 -04:00
Mathieu MoranandCopilot 261ef3f4db Revive yaris-obd: USB OBD adapter, real GPS/GNSS, offline map, hotspot, SQLite logging, dashcam retrieval
Squashed rewrite of the project revival work (replaces prior history on this
branch to remove personal data that had been accidentally committed - real
LAN IP, GPS coordinates, home WiFi SSID, and phone model). See PLAN.md for
full phase-by-phase details. Summary:

- Phase 2: adapt app_obd.py for a USB OBD-II adapter (was Bluetooth-only),
  auto-detect /dev/ttyUSB*, fix several pre-existing crash bugs.
- Phase 3/4: make the web UI work fully offline (vendored Socket.IO/Leaflet/
  Chart.js/FontAwesome, offline map tile downloader script, live GPS marker
  tracking fix).
- Phase 5: systemd deployment/autostart on the Pi.
- Phase 6: WiFi hotspot mode via NetworkManager (auto-switch between home
  WiFi and a local AP for in-car web UI access), mDNS hostname + port 80
  redirect so the UI is reachable at a plain hostname with no port number.
- Phase 7: fix app_db.py/app_sql.py bugs, wire up local SQLite trip logging.
- Phase 8: brand-agnostic USB dashcam file retrieval (lsblk transport-based
  detection, works with any dashcam brand/folder layout).
- Rewritten readme.md with a proper project overview.

Co-authored-by: Copilot <[email protected]>
2026-08-08 18:01:35 -04:00