305 lines
19 KiB
Markdown
305 lines
19 KiB
Markdown
# 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-XX` section per idea.** Keep numbering sequential.
|
||
- **Status field**: `IDEA` (brainstormed, not planned) → `PLANNED` (has an assigned phase) →
|
||
`IN PROGRESS` → `SHIPPED` (deployed + verified) or `WONTFIX`/`SUPERSEDED` as 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.
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
| ID | Status | Title | Phase |
|
||
|----|--------|-------|-------|
|
||
| FEAT-01 | `IDEA` | Parallel/concurrent chunked dashcam uploads | Phase 27 |
|
||
| FEAT-02 | `IDEA` | QR / claim-code device pairing flow | Phase 27 |
|
||
| FEAT-03 | `SHIPPED` | Manual start odometer fallback | Phase 27 |
|
||
| FEAT-04 | `IDEA` | Replace SIM868 2G with 4G LTE modem | Phase 27 |
|
||
| FEAT-05 | `SHIPPED` | DTC history synced to remote server | Phase 27 |
|
||
| FEAT-06 | `SHIPPED` | Trip ID column in history table | Phase 26 |
|
||
| FEAT-07 | `SHIPPED` | Phone-hotspot auto-connect docs | Phase 22 |
|
||
| FEAT-08 | `SHIPPED` | Predictable IP on phone hotspot | Phase 22 |
|
||
| FEAT-09 | `WONTFIX` | mDNS (yaris.local) on phone hotspot | — |
|
||
| FEAT-10 | `IDEA` | Home Assistant integration | unassigned |
|
||
| FEAT-11 | `SHIPPED` | Hotspot SSID/password settings + 5GHz WiFi role swap | Phase 27 |
|
||
| FEAT-12 | `SHIPPED` | Log OBD speed before GPS fix (rolling-start capture) | Phase 27 |
|
||
| FEAT-13 | `IDEA` | Flush uploaded tracking rows from local DB | unassigned |
|
||
| FEAT-14 | `SHIPPED` | Second T3U to replace onboard wlan0 (dual AC radios) | Phase 29 |
|
||
| FEAT-15 | `SHIPPED` | Clear DTC codes from the DTC page | Phase 29 |
|
||
| FEAT-16 | `SHIPPED` | Max-speed marker on trip replay map | Phase 29 |
|
||
|
||
---
|
||
|
||
## 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_KEY` onto 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**: `SHIPPED` 2026-08-11 (extended 2026-08-12)
|
||
- **Area**: Settings page, Dashboard, trip history, `modules/app_settings.py`, `modules/app_sql.py`,
|
||
`modules/app_trip.py`, `server/modules/db.py`, `static/js/history.js`
|
||
- **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/stats` response.
|
||
- **2026-08-12 — simulated odometer in trip history**: the trip replay scrubber now
|
||
shows an "Odometer" line below speed. Per-point odometer is the raw OBD value when
|
||
the vehicle reports one (PID 0xA6), otherwise a **continuous simulation**:
|
||
`baseline + Σ(prior trips' distance) + within-trip distance`. The trip-list
|
||
"Odometer" column uses the same continuous formula on both Pi and server (previously
|
||
the server hardcoded `None` and the Pi ignored the baseline). The 2013 Yaris doesn't
|
||
report PID 0xA6, so every point uses the simulated value.
|
||
|
||
### 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.py` GNSS 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.py` currently does.
|
||
|
||
### FEAT-05 — DTC history synced to remote server with code descriptions
|
||
- **Status**: `SHIPPED` 2026-08-12
|
||
- **Area**: `modules/app_upload.py`, `server/sql/migrate_phase27_dtc.sql`, `server/modules/db.py`, `server/app.py`, `server/templates/dtc.html`
|
||
- **Phase**: Phase 27
|
||
- **What**: Pi pushes current DTC snapshot to server via `POST /api/v1/dtc/batch`.
|
||
Server diffs against stored state — new codes inserted, existing updated, missing
|
||
codes auto-cleared. Portal has a new `/dtc` page showing code, description, MIL
|
||
state, active/cleared status, first/last seen timestamps, and manual delete.
|
||
Upload skips when OBD disconnected (avoids clearing server DTCs on Pi reboot).
|
||
Snapshot is hash-compared to avoid redundant uploads.
|
||
|
||
### FEAT-06 — Trip ID column in history table
|
||
- **Status**: `SHIPPED` 2026-08-11
|
||
- **Area**: `static/js/history.js`, `templates/history.html`, `server/templates/history.html`
|
||
- **Phase**: Phase 26
|
||
- **What**: Narrow `#ID` column on server history (hidden on Pi via `data-show-id`).
|
||
Checkbox column and batch-delete restored on server only.
|
||
|
||
### FEAT-07 — Phone-hotspot auto-connect documentation
|
||
- **Status**: `SHIPPED` 2026-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".
|
||
- **Known limitation (2026-08-12)**: the phone can't host the hotspot *and* connect to
|
||
the Pi's AP at the same time — that creates a WiFi-sharing/routing loop and the Pi
|
||
loses internet (`NameResolutionError` on uploads). To use the phone hotspot as the
|
||
Pi's uplink, the phone must be LTE-only (WiFi off). Browse the Pi UI from a second
|
||
device on the AP instead. Also, the phone's DHCP DNS was flaky for the `.dev` tunnel,
|
||
so `phone-hotspot` now forces `8.8.8.8` + `1.1.1.1` (see `deploy/yaris_uplink.py`).
|
||
|
||
### FEAT-08 — Predictable IP on phone hotspot (DHCP client-id)
|
||
- **Status**: `SHIPPED` 2026-08-11 (Phase 22)
|
||
- **Area**: `deploy/yaris_uplink.py`, phone-hotspot NM profile
|
||
- **What**: `dhcp-client-id=yaris-obd` in 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**: `WONTFIX` 2026-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.
|
||
|
||
### FEAT-10 — Home Assistant integration
|
||
- **Status**: `IDEA`
|
||
- **Area**: `modules/app_homeassistant.py` (new), `server/` (API endpoints), Pi-side MQTT/HTTP
|
||
- **Phase**: unassigned
|
||
- **Requested**: owner — wants the car's live telemetry and status visible in Home Assistant
|
||
dashboards alongside other smart-home devices.
|
||
- **Idea**: expose yaris-obd data (speed, RPM, coolant temp, fuel level, GPS position, DTC
|
||
alerts, ignition state, trip stats, cellular signal, etc.) as Home Assistant entities so
|
||
they appear automatically via MQTT discovery or a REST-based integration. The Pi already
|
||
collects all this data — the integration just needs to publish it in a format Home
|
||
Assistant can consume.
|
||
- **Possible approaches** (to scope later):
|
||
- **MQTT discovery**: Pi publishes to a local MQTT broker (e.g. Mosquitto on the same
|
||
network or on the HA host) with Home Assistant's auto-discovery topic schema
|
||
(`homeassistant/sensor/yaris/.../config`). HA picks up the entities automatically with
|
||
zero manual YAML. Works well on home WiFi; not available on phone hotspot or cellular.
|
||
- **REST API integration**: a custom Home Assistant integration (HACS or core) that polls
|
||
the Pi's `/api/stats` (or a new `/api/v1/ha/state` endpoint on the server) periodically.
|
||
Works from anywhere the server is reachable, including remotely via the self-hosted
|
||
server.
|
||
- **Hybrid**: MQTT when on home WiFi (real-time, low-latency), REST via server as a
|
||
fallback for remote/cellular visibility.
|
||
- **Entity ideas**:
|
||
- `sensor.yaris_speed` (km/h), `sensor.yaris_rpm`, `sensor.yaris_coolant_temp` (°C)
|
||
- `sensor.yaris_fuel_level` (%), `sensor.yaris_odometer` (km)
|
||
- `device_tracker.yaris_location` (lat/lon from GPS)
|
||
- `binary_sensor.yaris_ignition` (on/off), `binary_sensor.yaris_mil` (check engine light)
|
||
- `sensor.yaris_dtc_count`, `binary_sensor.yaris_dtc_active` (any active DTCs)
|
||
- `sensor.yaris_cellular_signal` (dBm or %), `sensor.yaris_uplink_mode` (home/phone/cell)
|
||
- `sensor.yaris_trip_distance`, `sensor.yaris_trip_duration` (current trip)
|
||
- `device_tracker.yaris_phone_hotspot` (when connected via phone hotspot — confirms car
|
||
is near the phone)
|
||
- **Outstanding considerations**:
|
||
- MQTT path only works when the Pi is on the same LAN as Home Assistant (home WiFi) — not
|
||
in the car on its own AP or cellular. This may be fine for "car is home" use cases
|
||
(charging status, maintenance reminders, trip summaries after returning).
|
||
- REST path via the self-hosted server works remotely but adds latency and depends on the
|
||
server being up.
|
||
- Decide whether to publish directly from the Pi or from the server (server already has
|
||
post-upload trip data; Pi has real-time data the server doesn't).
|
||
- Home Assistant OS vs container vs core install — MQTT discovery is universal, REST
|
||
would need a custom component or HACS add-on.
|
||
- Keep the integration opt-in and lightweight — don't add MQTT dependencies to the core
|
||
app.py startup unless the user explicitly configures it.
|
||
|
||
|
||
### FEAT-11 — Hotspot SSID/password settings + 5GHz WiFi role swap
|
||
- **Status**: `SHIPPED` 2026-08-12
|
||
- **Area**: `app.py`, `templates/settings.html`, `static/js/settings.js`,
|
||
`deploy/yaris-hotspot.sudoers`, `deploy/yaris_uplink.py`, `deploy/install_netwatch.sh`,
|
||
`modules/app_network.py`
|
||
- **Phase**: Phase 27
|
||
- **What**: Two related changes:
|
||
1. **Hotspot settings UI** — the Pi Settings page "In-car access" card now has SSID +
|
||
password fields (password write-only). `GET /api/hotspot` reads the current SSID via
|
||
nmcli; `POST /api/hotspot` updates SSID/password and restarts the AP immediately.
|
||
Backed by `deploy/yaris-hotspot.sudoers` (privileged nmcli on the `Hotspot-local`
|
||
profile).
|
||
2. **WiFi role swap** — the fast TP-Link T3U (wlan1) now hosts the in-car AP on **5GHz**
|
||
("vroom vroom yaris de course" at 10.42.0.1) for fast phone access (Android dev, video
|
||
browsing); the weak onboard BCM43438 (wlan0) carries the internet uplink (home WiFi
|
||
"BuzzBis" + phone hotspot, static IP 192.168.50.220). This was done because the AP on
|
||
the onboard radio was too slow for interactive Android work. Tradeoff: away-from-home
|
||
uploads now run over the weak radio (accepted — background task). A single radio cannot
|
||
be AP + client at once, so the phone-hotspot uplink must stay on wlan0.
|
||
- **Files**: `yaris_uplink.py` (PRIMARY=wlan0, AP_INTERFACE=wlan1, AP_CONNECTION=Hotspot-local),
|
||
`app_network.py` (uplink on wlan0, AP on wlan1), `install_netwatch.sh` (rebinds profiles).
|
||
|
||
|
||
### FEAT-12 — Log OBD speed before GPS fix (rolling-start capture)
|
||
- **Status**: `SHIPPED` 2026-08-13
|
||
- **Area**: `modules/app_sql.py` (`_log_loop`, `insert_tracking`), `modules/app_trip.py`
|
||
(`normalize_tracking_rows`, `_segment`, `route_points`)
|
||
- **What**: The tracking logger previously only wrote rows once GPS had a fix, so a rolling
|
||
start or mid-drive reboot lost the first ~1.5–2 min of movement (boot + GPS cold start).
|
||
Now, while GPS has no fix but OBD speed > 1 km/h, the logger writes speed-only rows with
|
||
NULL coordinates; trip building treats them as OBD-motion events (zero GPS distance). The
|
||
route polyline drops these rows (no position to draw).
|
||
- **Server parity note**: server `compute_trips_for_device` and `get_trip_route` already filter
|
||
`gps_lat IS NOT NULL`, so they safely ignore the NULL-coordinate rows — but the server's
|
||
recomputed trips don't yet include the speed-only leading motion (follow-up if needed).
|
||
|
||
|
||
### FEAT-13 — Flush uploaded tracking rows from local DB
|
||
- **Status**: `IDEA`
|
||
- **Area**: `modules/app_sql.py` (`tracking` table), `modules/app_upload.py`
|
||
- **Phase**: unassigned
|
||
- **What**: The local SQLite `tracking` table keeps every raw row forever — rows are only
|
||
marked `UPLOADED=1`, never deleted. Once rows are confirmed uploaded to the server, provide
|
||
a way to flush them locally (e.g. a settings toggle + retention window) so the local DB stays
|
||
bounded over years of driving.
|
||
- **Considerations**:
|
||
- Trip summaries (`trips` table) are derived and can be kept independently; but the local
|
||
route-replay polyline is built from raw `tracking` rows, so purging rows removes local route
|
||
detail. The server keeps full `tracking_points`, so replay stays available on the portal.
|
||
- Must be opt-in and only delete rows that are `UPLOADED=1` (and older than a grace window)
|
||
so a failed upload or re-send never loses data.
|
||
- Tracking data is small (~90 B/row, ~a few MB/month) so this is long-term hygiene, not
|
||
urgent — imported dashcam videos are the real disk consumer.
|
||
|
||
|
||
### FEAT-14 — Second T3U to replace onboard wlan0 (dual AC radios)
|
||
- **Status**: `SHIPPED` 2026-08-14
|
||
- **Area**: hardware + `deploy/yaris_uplink.py`, `deploy/install_netwatch.sh`, `modules/app_network.py`, `deploy/90-yaris-uplink`
|
||
- **Phase**: Phase 29
|
||
- **What**: Owner added a second TP-Link Archer T3U (RTL8812BU) to replace the onboard
|
||
BCM43438 as the internet uplink. Both radios are now AC1300 T3U dongles — `wlan1` (T3U #1)
|
||
hosts the 5GHz in-car AP, `wlan2` (T3U #2) carries the uplink (home-wifi + phone-hotspot),
|
||
and the onboard `wlan0` is retired to a weak fallback. Removes the old tradeoff where
|
||
away-from-home uploads ran over the weak onboard radio.
|
||
- **Changes**: `PRIMARY_INTERFACE=wlan2` / `FALLBACK_INTERFACE=wlan0` / `AP_INTERFACE=wlan1`
|
||
in `yaris_uplink.py` + `app_network.py`; `install_netwatch.sh` rebinds `home-wifi` +
|
||
`phone-hotspot` to wlan2 and recreates the `home-wifi-fb` fallback on wlan0; the NM
|
||
dispatcher (`90-yaris-uplink`) now listens on `wlan0|wlan1|wlan2`.
|
||
- **Verified**: the second T3U enumerates as `wlan2` (rtl88x2bu) and
|
||
`vcgencmd get_throttled` = `0x0` (no undervoltage with both dongles powered).
|
||
- **Open item**: interface-name pinning relies on USB enumeration order; if the two T3Us ever
|
||
swap ports, `wlan1`/`wlan2` swap — a MAC-based udev/`.link` rule is the robust follow-up.
|
||
|
||
|
||
### FEAT-15 — Clear DTC codes from the DTC page
|
||
- **Status**: `SHIPPED` 2026-08-13
|
||
- **Area**: `modules/app_obd.py`, `modules/app_sql.py`, `app.py`, `templates/dtc.html`
|
||
- **Phase**: Phase 29
|
||
- **What**: The Pi `/dtc` page now has a **Clear codes** button that sends OBD mode 04
|
||
(`CLEAR_DTC`) to the ECU and resets both the live and persisted DTC state, so codes can be
|
||
cleared right after a repair without a separate scanner. If the adapter isn't connected to
|
||
the car ECU it reports "not connected" (409), and if a fault is still physically present the
|
||
codes legitimately re-appear on the next sensor poll.
|
||
- **Files**: `clear_dtc_codes()` in `app_obd.py` (mode 04 + in-memory/socket reset),
|
||
`clear_dtc_state()` in `app_sql.py` (marks active rows `IS_SET=0`, resets `dtc_mil`),
|
||
`POST /api/dtc/clear` in `app.py`, and the button + confirm/status JS in `templates/dtc.html`.
|
||
|
||
|
||
### FEAT-16 — Max-speed marker on trip replay map
|
||
- **Status**: `SHIPPED` 2026-08-15
|
||
- **Area**: `static/js/history.js`
|
||
- **Phase**: Phase 29
|
||
- **What**: when a trip's route loads, the replay map now pins the fastest point with an
|
||
amber circle + a permanent "Max speed: X km/h" tooltip. It uses the per-point speed (OBD
|
||
when available, otherwise the smoothed GPS-derived value), so it matches the trip summary's
|
||
`max_speed_kmh`. Works identically on the Pi and the server portal (shared `history.js`).
|
||
|
||
|