11 KiB
yaris-obd Feature Requests
Ideas and requests for new features (distinct from bugs, which belong in BUGS.md, and the
phase-by-phase implementation history in PLAN.md). Use this file to record anything that should
be built eventually but isn't an active roadmap phase yet. When a feature gets picked up, create a
dedicated PLAN.md phase (or fold it into the relevant existing work) and mark it here.
How to use this file
- One
## FEAT-XXsection per idea. Keep numbering sequential. - Status field:
IDEA(brainstormed, not planned) →PLANNED(has an assigned phase) →IN PROGRESS→SHIPPED(deployed + verified) orWONTFIX/SUPERSEDEDas appropriate. - Relate to roadmap: when a feature lands in a phase, note the phase here and drop a link back here from PLAN.md so the two stay in sync.
- Keep each entry small and one-idea-per-entry so it's easy to pick up and scope.
Feature ideas
FEAT-01 — Parallel/concurrent chunked dashcam uploads
- Status:
IDEA - Area:
modules/app_upload.py(Pi upload client) - Phase: Phase 27
- Requested: noted in Phase 10 of PLAN.md as a possible future optimization; not yet requested explicitly by the owner.
- Idea: upload multiple dashcam chunks (and/or multiple files) concurrently instead of the current strictly sequential one-chunk-then-one-file at a time. Would speed up the multi-hour full-backlog drain of a large local dashcam archive, at the cost of more complexity (bounded concurrency, per-file state, failure handling for the individual concurrent workers).
- Outstanding considerations: memory budget on the Pi (~900MB, no swap — must stay streaming), and whether the sequential pace is actually annoying enough in practice to justify the added complexity.
FEAT-02 — QR / claim-code device pairing flow
- Status:
IDEA - Area: server device provisioning + Pi credential setup (Phase 25.5c)
- Phase: Phase 27
- Requested: discussed in Phase 25.5c as a possible follow-up to the manual copy/paste API-key provisioning.
- Idea: zero-manual-copy provisioning of
YARIS_SERVER_URL/YARIS_DEVICE_NAME/YARIS_API_KEYonto the Pi — e.g. the portal shows a short-lived claim code / QR that the Pi app (or owner) enters/scans once to adopt the device, instead of typing credentials by hand. - Outstanding considerations: bigger scope than the current copy/paste flow; ship copy/paste first, add pairing only if provisioning still feels annoying.
FEAT-03 — Manual start odometer fallback when OBD odometer is unavailable
- Status:
SHIPPED2026-08-11 - Area: Settings page, Dashboard,
modules/app_settings.py,modules/app_sql.py - Phase: Phase 27
- What: Settings page now has an "Odometer baseline (km)" field. The app stores
this value and computes
odometer_km = baseline + cumulative trip distance. Dashboard shows "(manual)" label when using baseline. When baseline is 0, falls back to live OBD reading (the original behavior). Also appears in/api/statsresponse.
FEAT-04 — Replace SIM868 2G GSM hat with 4G LTE modem (Huawei E3372h-153)
- Status:
IDEA - Area: modems / uplink (Pi
modules/app_cellular.py,modules/app_gps.py, uplink switching) — replaces the current SIM868 GSM/GNSS HAT + cellular fallback path - Phase: Phase 27
- Requested: owner — just purchased a Huawei E3372h-153 4G LTE Modem. The 2G/3G-only SIM868 hat will not work in Canada (2G networks are decommissioned), so the plan is to make the 4G modem the working cellular uplink instead.
- Idea: integrate the Huawei E3372h-153 as the primary cellular data uplink, replacing reliance on the SIM868's GSM (AT+HTTP) path. The E3372h-153 is a USB "stick" modem — likely supported via Realtek / cdc_ether / usb-storage based drivers and exposes a dial-up or LTE dongle interface the Pi can use for connectivity (e.g. via NetworkManager / ModemManager, or a static APN config).
- Outstanding considerations:
- Determine the E3372h-153's local mode vs stick/dial mode and the correct Linux driver/interface (hierarchical USB mode switching may be needed; it's the "153" variant which may use the RNDIS / ECM / CDC-NCM profile).
- Whether to run it as the primary uplink or just another option in the existing phone-hotspot / home-wifi / local-AP priority chain.
- What happens to the SIM868 — keep it purely for its GPS/GNSS role (it's the PWRKEY-toggled
GNSS receiver on
/dev/serial0) while dropping its 2G GSM cellular path, vs removing it entirely. - The SIM868's
app_gps.pyGNSS positioning must keep working (it's the car's GPS source) even if the 2G-modem half is retired — separate the two concerns. - Keep this feature as-is (2G/GSM fallback) for countries where 2G/3G still works — don't remove the existing cellular fallback code; gate it so the 2G path remains available there.
- LTE SIM plan/APN specifics for Canadian carriers (Rogers/Bell/Telus) and whether the modem can
run the Pi's hotspot/SSID the same way
app_network.pycurrently does.
FEAT-05 — DTC history synced to remote server with code descriptions
-
Status:
IDEA -
Area:
modules/app_upload.py,modules/app_sql.py,server/sql/,server/modules/db.py,server/app.py, server portal templates -
Phase: Phase 27
-
Requested: 2026-08-11 — owner wants DTC codes persisted to the server (not just local SQLite) with code + description, surviving until user deletes them or OBD reports the code cleared.
-
Current state (2026-08-11):
- Pi:
app_obd.pypolls DTCs from ECU →app_sql.save_dtc_state()persists MIL + codes (code, description, IS_SET, FIRST_SEEN_AT, LAST_SEEN_AT) to local SQLitedtctable. - Pi:
app_upload.pyuploads tracking rows and dashcam files — NO DTC upload path exists. - Server: NO
dtc_eventstable, NO DTC API, NO portal DTC page.
- Pi:
-
Design:
Server schema (
server/sql/migrate_phase26_dtc.sql):CREATE TABLE IF NOT EXISTS dtc_events ( id SERIAL PRIMARY KEY, device_id INTEGER NOT NULL REFERENCES devices(id) ON DELETE CASCADE, code VARCHAR(10) NOT NULL, description TEXT NOT NULL DEFAULT '', mil_on BOOLEAN NOT NULL DEFAULT FALSE, is_active BOOLEAN NOT NULL DEFAULT TRUE, first_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(), last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(), cleared_at TIMESTAMPTZ, UNIQUE (device_id, code) );Server API (
server/app.py):POST /api/v1/dtc/batch(device auth): receives current DTC snapshot from Pi. Body:{"mil_on": true/false, "codes": [{"code": "P0301", "description": "Cylinder 1 Misfire"}, ...]}- Insert new codes, update
last_seen_atfor existing active codes. - Mark any previously-active codes NOT in this batch as
is_active=false, cleared_at=now(). - Return
{received: N, cleared: M, unchanged: K}.
- Insert new codes, update
GET /api/v1/portal/dtc(user auth): list all DTC events for configured device.DELETE /api/v1/portal/dtc/<id>(user auth): manual deletion.
Server portal: new DTC page or section showing code, description, MIL state, first/last seen, active/cleared status, cleared timestamp.
Pi upload (
modules/app_upload.py):- New
_upload_dtc_snapshot()— called after tracking batch in_upload_loop(). - Only uploads when the local DTC snapshot differs from last-uploaded (hash or version compare).
- Reuses same
_credentials()/_headers()as tracking uploads. - Same WiFi-first, cellular-fallback (if configured) path as tracking batches.
-
Deduplication logic: server-side per
(device_id, code)unique key. Pi sends the full current snapshot each time. Server diffs: new codes = insert, existing = touch last_seen_at, missing from snapshot = mark cleared. This means if a code disappears from the ECU, it auto-clears on the server on the next upload — no manual "clear" step needed. -
Manual deletion: only via the server portal delete button. Cleared codes stay visible as history. The Pi never deletes from the server automatically.
-
Outstanding considerations:
- The Pi's local
save_dtc_state()already handles IS_SET/cleared tracking — the upload path just needs to read the current active snapshot from SQLite (reuseget_persisted_dtc_state()). - DTC descriptions come directly from the ECU (python-obd's
GET_DTCresponse) — they're the standard SAE J2012 descriptions, no external lookup needed. - Should we upload on every poll (every ~2s OBD cycle) or batch? Answer: batch. Upload alongside tracking batches (every 30s idle, 1s catchup). DTCs don't change mid-drive that often.
- First upload after Pi reboot with no OBD connected: snapshot is empty → server marks all
previously-active codes as cleared. Is that desired? Probably not — should skip upload when
OBD is disconnected/unavailable (the Pi already knows this from
connectionstate).
- The Pi's local
FEAT-08 — Predictable IP on phone hotspot (DHCP client-id)
- Status:
SHIPPED2026-08-11 (Phase 22) - Area:
deploy/yaris_uplink.py, phone-hotspot NM profile - What:
dhcp-client-id=yaris-obdin the NM keyfile gives the Pi a consistent DHCP lease. The "Last phone IP" link on Settings shows the current address. Pixel testing confirmed same IP across disconnects.
FEAT-09 — mDNS (yaris.local) on phone hotspot
- Status:
WONTFIX2026-08-12 — hardware/OS limitation - Area: Avahi, phone-hotspot NM profile
- What: Phone hotspot hosts (Android, iOS) don't relay multicast DNS. Avahi publishes correctly on wlan0 AP and home WiFi. Settings "Last phone IP" link is the workaround. Cannot be fixed in software — this is a phone-OS limitation.
Ideas that landed
(No entries yet — shipped features land here. Keep the original idea text intact and add the shipped phase/date.)
FEAT-07 — Phone-hotspot auto-connect documentation
- Status:
SHIPPED2026-08-11 (already implemented in Phase 22, documented here) - Area:
deploy/yaris_uplink.py, Settings page, netwatch timer - What: The Pi auto-connects to a saved phone hotspot on wlan1 within ~60s of it appearing in range, and falls back to home-wifi when it disappears. The wlan0 AP stays up regardless. Test flow: Settings → save hotspot name + password → "Wait for hotspot" → enable phone hotspot → verify mode changes to "Phone hotspot".
FEAT-06 — Trip ID column in history table
- Status:
SHIPPED2026-08-11 - Area:
static/js/history.js,templates/history.html,server/templates/history.html - Phase: Phase 26
- What: Narrow
#IDcolumn on server history (hidden on Pi viadata-show-id). Checkbox column and batch-delete restored on server only.