Rework Phases 12-17 for efficiency, add QOL phases (power resilience, watchdog, trip history, Pi health, alerts, settings)
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]>
This commit is contained in:
@@ -661,9 +661,41 @@ not fixable). Remove:
|
|||||||
avoid rehashing its 20GB+ backlog every loop), `DASHCAM_CHUNK_SIZE`/Cloudflare 100MB
|
avoid rehashing its 20GB+ backlog every loop), `DASHCAM_CHUNK_SIZE`/Cloudflare 100MB
|
||||||
workaround - none of that is relay-specific.
|
workaround - none of that is relay-specific.
|
||||||
|
|
||||||
### Phase 13: Dashcam USB file browser (list + delete) — 🚧 PLANNED
|
### Phase 13: Power-loss resilience & watchdog — 🚧 PLANNED
|
||||||
|
**New phase, not code-dependent on anything else — OS/hardware-level, can be done anytime,
|
||||||
|
ideally before the Pi lives in the car full-time.** A car cuts power abruptly at every key-off;
|
||||||
|
nothing in the project currently protects against that, and repeated unclean power loss is a
|
||||||
|
classic cause of SD card corruption on embedded Pi projects. Two complementary angles:
|
||||||
|
- **Filesystem hardening**: convert the Pi's root filesystem to read-only with a writable overlay
|
||||||
|
(`overlayroot`/`raspi-config`'s built-in overlay FS option), so an abrupt power cut can no longer
|
||||||
|
corrupt the OS itself. App data that must persist (`db/sql/`, `dash/videos/`, logs) needs to
|
||||||
|
live on an explicitly writable partition/bind-mount carved out of the overlay, since those
|
||||||
|
still need real writes.
|
||||||
|
- **Clean shutdown before power loss**: either (a) a small delayed-shutdown power module/circuit
|
||||||
|
(holds 5V for a few seconds after ignition-off so the Pi can run `shutdown -h now` cleanly), or
|
||||||
|
(b) if the SIM868 HAT or another ADC/GPIO source can sense ignition/voltage state, a software
|
||||||
|
voltage-drop watcher that triggers a clean shutdown proactively. Exact approach TBD - depends
|
||||||
|
on what's easiest to wire into the existing power setup.
|
||||||
|
- **Hardware watchdog**: enable the Pi's built-in `bcm2835_wdt` watchdog (via `systemd`'s
|
||||||
|
`RuntimeWatchdogSec`/`watchdog-device` support) so a fully hung app or kernel gets a hard reboot
|
||||||
|
automatically instead of sitting dead in the car until someone notices.
|
||||||
|
|
||||||
|
### Phase 14: UI design-system foundation — 🚧 PLANNED
|
||||||
|
**New phase, pulled forward from the old "do the whole redesign at the end" plan.** Building the
|
||||||
|
Phase 15/16 file browsers (and later the trip-history/Pi-health/settings pages) against the
|
||||||
|
current old admin-template style just means rebuilding the same UI twice once the full redesign
|
||||||
|
(Phase 22) happens. Instead, do a *small, scoped* slice of the redesign right now: a shared page
|
||||||
|
layout/shell plus one reusable list/table component (sortable columns, per-row action buttons,
|
||||||
|
delete-with-confirmation pattern, empty-state messaging) that every subsequent list-based feature
|
||||||
|
in this plan (dashcam browser, video browser, trip history, settings) can be built on directly,
|
||||||
|
instead of writing bespoke list/delete UI code from scratch each time. Not a full redesign of
|
||||||
|
every existing page yet - just establishes the pattern once so nothing built after this point
|
||||||
|
needs to be redone in Phase 22.
|
||||||
|
|
||||||
|
### Phase 15: Dashcam USB file browser (list + delete) — 🚧 PLANNED
|
||||||
Replace the current all-or-nothing "Import videos" flow's blind spot (no visibility into what's
|
Replace the current all-or-nothing "Import videos" flow's blind spot (no visibility into what's
|
||||||
actually on the camera) with a real file browser for the mounted USB dashcam device:
|
actually on the camera) with a real file browser for the mounted USB dashcam device, built on the
|
||||||
|
Phase 14 shared list component:
|
||||||
- New endpoint(s) in `modules/app_dash.py` to list every video file on the mounted dashcam
|
- New endpoint(s) in `modules/app_dash.py` to list every video file on the mounted dashcam
|
||||||
(relative path, size, modified time) without copying anything - reuses the existing
|
(relative path, size, modified time) without copying anything - reuses the existing
|
||||||
`find_video_files()` walk, pointed at the dashcam's mount point instead of the local
|
`find_video_files()` walk, pointed at the dashcam's mount point instead of the local
|
||||||
@@ -676,13 +708,13 @@ actually on the camera) with a real file browser for the mounted USB dashcam dev
|
|||||||
list with a delete button per row, a "Delete all" button behind a confirmation dialog (real
|
list with a delete button per row, a "Delete all" button behind a confirmation dialog (real
|
||||||
data loss risk - no undo).
|
data loss risk - no undo).
|
||||||
- Explicitly deferred/out of scope: no in-browser preview/playback of files still on the
|
- Explicitly deferred/out of scope: no in-browser preview/playback of files still on the
|
||||||
dashcam itself (only after import - see Phase 14). No changes to the USB
|
dashcam itself (only after import - see Phase 16). No changes to the USB
|
||||||
select-mode/data-communication toggle behavior - the user replugs power manually to return the
|
select-mode/data-communication toggle behavior - the user replugs power manually to return the
|
||||||
camera to recording mode, as they already do.
|
camera to recording mode, as they already do.
|
||||||
|
|
||||||
### Phase 14: Local imported-video browser + player — 🚧 PLANNED
|
### Phase 16: Local imported-video browser + player — 🚧 PLANNED
|
||||||
Same file-browser treatment for videos already imported to the Pi's own disk
|
Same file-browser treatment for videos already imported to the Pi's own disk
|
||||||
(`dash/videos/`, populated by `import_dashcam()`):
|
(`dash/videos/`, populated by `import_dashcam()`), built on the Phase 14 shared list component:
|
||||||
- List endpoint (reuses `find_video_files()` against `app_dash.DEFAULT_DESTINATION`) showing
|
- List endpoint (reuses `find_video_files()` against `app_dash.DEFAULT_DESTINATION`) showing
|
||||||
relative path, size, modified time, and upload status (cross-check against
|
relative path, size, modified time, and upload status (cross-check against
|
||||||
`app_sql.dashcam_file_marked_uploaded()` - so it's visible at a glance which imported clips
|
`app_sql.dashcam_file_marked_uploaded()` - so it's visible at a glance which imported clips
|
||||||
@@ -698,8 +730,18 @@ Same file-browser treatment for videos already imported to the Pi's own disk
|
|||||||
- UI: a `/dash` card (or a dedicated sub-page if the list gets long) with a file list, a
|
- UI: a `/dash` card (or a dedicated sub-page if the list gets long) with a file list, a
|
||||||
"Play" action that opens the video inline, and a delete button per row with a confirmation
|
"Play" action that opens the video inline, and a delete button per row with a confirmation
|
||||||
prompt.
|
prompt.
|
||||||
|
- **QOL: video thumbnails.** Scrolling a list of `VID_00234.MOV`-style filenames to find a
|
||||||
|
specific clip is rough. Grab one low-res frame per file via `ffmpeg` (cheap, done once per file
|
||||||
|
and cached, not on every page load) so the browser shows an actual thumbnail per row instead of
|
||||||
|
just a filename.
|
||||||
|
- **QOL: retention/auto-cleanup policy.** Once a file is confirmed uploaded to the remote server,
|
||||||
|
it's safe to free local space. Add an optional automatic cleanup (configurable via the Phase 21
|
||||||
|
Settings page - e.g. "delete local copies older than N days once uploaded", off by default)
|
||||||
|
so the Pi's limited storage doesn't need to be babysat manually as the dashcam backlog grows.
|
||||||
|
|
||||||
### Phase 15: OBD real-hardware readiness (code hardening) — 🚧 PLANNED
|
### Phase 17: OBD real-hardware readiness (code hardening) — 🚧 PLANNED
|
||||||
|
**Independent of everything else in this plan — only touches `app_obd.py`/`app_events.py`, no UI
|
||||||
|
dependency for the backend part, so this can be done anytime/in parallel with the phases above.**
|
||||||
Nothing has been installed or tested in the actual 2013 Yaris yet - `modules/app_obd.py` has
|
Nothing has been installed or tested in the actual 2013 Yaris yet - `modules/app_obd.py` has
|
||||||
only ever been tested standalone on the Pi with nothing plugged into the OBD-II port (correctly
|
only ever been tested standalone on the Pi with nothing plugged into the OBD-II port (correctly
|
||||||
reports "no connection to car"). Per explicit user decision, this phase is **code hardening
|
reports "no connection to car"). Per explicit user decision, this phase is **code hardening
|
||||||
@@ -729,53 +771,104 @@ all in `modules/app_obd.py` / `modules/app_events.py`:
|
|||||||
- **Add a small connect-time diagnostic log** (ELM327 firmware version + negotiated protocol,
|
- **Add a small connect-time diagnostic log** (ELM327 firmware version + negotiated protocol,
|
||||||
both available from `python-obd`'s connection object) written once per successful connect -
|
both available from `python-obd`'s connection object) written once per successful connect -
|
||||||
useful evidence to sanity-check against Toyota's expected protocol on the very first real test.
|
useful evidence to sanity-check against Toyota's expected protocol on the very first real test.
|
||||||
- **Expand the data pulled from the car beyond speed/RPM**, to feed the richer dashboard planned
|
- **Expand the data pulled from the car beyond speed/RPM** (backend only - the dashboard cards
|
||||||
in Phase 17: coolant temperature, fuel level, throttle position, and DTC/MIL status (check-
|
displaying this land in Phase 22 once the redesign reaches them): coolant temperature, fuel
|
||||||
engine light on/off + stored trouble codes, reusing/wiring up the already-scaffolded but
|
level, throttle position, and DTC/MIL status (check-engine light on/off + stored trouble codes,
|
||||||
currently-empty `/dtc` page and `GET_DTC` command). **Odometer/mileage is not guaranteed** -
|
reusing/wiring up the already-scaffolded but currently-empty `/dtc` page and `GET_DTC` command).
|
||||||
the standard OBD-II mode 1 PID for total odometer (0xA6) was only added to the SAE J1979 spec
|
**Odometer/mileage is not guaranteed** - the standard OBD-II mode 1 PID for total odometer
|
||||||
in later revisions and is inconsistently supported across manufacturers/years; whether the
|
(0xA6) was only added to the SAE J1979 spec in later revisions and is inconsistently supported
|
||||||
2013 Yaris's ECU exposes it at all can only be confirmed once tested against the real car
|
across manufacturers/years; whether the 2013 Yaris's ECU exposes it at all can only be
|
||||||
(falls under "code hardening only" for now - add the query with graceful "unsupported" handling
|
confirmed once tested against the real car (falls under "code hardening only" for now - add
|
||||||
rather than assuming it will work).
|
the query with graceful "unsupported" handling rather than assuming it will work).
|
||||||
|
|
||||||
### Phase 16: Complete web UI redesign — 🚧 PLANNED
|
### Phase 18: Trip history & replay — 🚧 PLANNED
|
||||||
|
**New phase.** Right now the `tracking` table (Phase 7) is just a raw stream of GPS/speed points
|
||||||
|
with no concept of a discrete "trip" - there's no way to look back and see "trip #47, left home
|
||||||
|
8:03am, arrived work 8:31am, 22km." Add:
|
||||||
|
- Trip boundary detection: group existing tracking rows into discrete trips based on speed>0
|
||||||
|
gaps (a simple, dependency-free heuristic - e.g. a gap of N minutes with no motion ends a trip),
|
||||||
|
computed either live as rows are logged or in a batch pass over existing data. Does not need to
|
||||||
|
wait on Phase 17's OBD hardening - can ship with GPS-only boundary detection first, refine with
|
||||||
|
ignition-on/off signals from OBD later if useful.
|
||||||
|
- A `trips` table (start/end time, start/end coordinates, distance, duration) in
|
||||||
|
`modules/app_sql.py`.
|
||||||
|
- A new history page/list (built on the Phase 14 shared list component) showing past trips, and
|
||||||
|
a map replay view (reusing the existing offline-tile Leaflet setup from Phase 3/4) that draws
|
||||||
|
the recorded route for a selected trip.
|
||||||
|
|
||||||
|
### Phase 19: Pi health monitoring card — 🚧 PLANNED
|
||||||
|
**New phase, small and standalone - no dependencies.** CPU temperature, free disk space, uptime,
|
||||||
|
and RAM usage are all cheap to read (`vcgencmd measure_temp`, `psutil`/`/proc` stats) and cheap to
|
||||||
|
display, but currently invisible - the only way to notice a problem (thermal throttling in a hot
|
||||||
|
car, an SD card filling up) today is to SSH in and check manually. Add a small backend endpoint
|
||||||
|
and a dashboard card (built on the Phase 14 component set) surfacing these at a glance. Also
|
||||||
|
feeds directly into Phase 20's alerting.
|
||||||
|
|
||||||
|
### Phase 20: Alerts/notifications — 🚧 PLANNED
|
||||||
|
**New phase - depends on Phases 16/17/19 existing first**, since it needs real data sources to
|
||||||
|
alert on. Right now, finding out about a problem (check-engine light on, dashcam SD card nearly
|
||||||
|
full, upload backlog growing unbounded, Pi overheating, GPS fix lost for a long stretch) requires
|
||||||
|
manually opening the web UI. Add a lightweight push-notification integration - no new
|
||||||
|
infrastructure needed, just an outbound webhook to something like `ntfy.sh` or a Telegram bot -
|
||||||
|
fired on a handful of conditions:
|
||||||
|
- DTC/MIL status changes to "on" (from Phase 17's expanded OBD data).
|
||||||
|
- Dashcam USB storage or local `dash/videos/` disk usage crossing a configurable threshold.
|
||||||
|
- Upload backlog (pending tracking rows or dashcam files) growing past a configurable size,
|
||||||
|
suggesting the Pi's been offline/uploading too slowly for a while.
|
||||||
|
- Pi CPU temperature crossing a configurable threshold (from Phase 19).
|
||||||
|
- GPS fix lost for longer than a configurable duration while the car appears to be moving
|
||||||
|
(OBD speed > 0 with no fix - needs Phase 17's data).
|
||||||
|
Webhook target/thresholds configurable via the Phase 21 Settings page rather than hardcoded.
|
||||||
|
|
||||||
|
### Phase 21: Settings page — 🚧 PLANNED
|
||||||
|
**New phase - depends on Phase 14's shared components, and benefits from Phases 16/20 existing**
|
||||||
|
so there's real configuration to consolidate. Several settings currently only exist as
|
||||||
|
SSH-edited files or scattered individual toggles (dashcam upload pause switch on `/dash`,
|
||||||
|
cellular APN in `db/upload_creds.env`, hotspot SSID/password via `nmcli` directly) or don't exist
|
||||||
|
yet (retention days from Phase 16, alert webhook/thresholds from Phase 20). Add one dedicated
|
||||||
|
Settings page consolidating anything reasonably safe to expose over the local-only web UI:
|
||||||
|
upload toggle, cellular APN, local video retention policy, alert webhook URL + thresholds. WiFi
|
||||||
|
SSID/password changes likely stay out of scope (higher-risk to expose over a UI that could lock
|
||||||
|
the Pi out of its own network if fat-fingered) unless it turns out to be easy/safe to add later.
|
||||||
|
|
||||||
|
### Phase 22: Finish web UI redesign — 🚧 PLANNED
|
||||||
The current `templates/`/`static/` UI is an old, mostly-unmodified admin dashboard template
|
The current `templates/`/`static/` UI is an old, mostly-unmodified admin dashboard template
|
||||||
(SB Admin 2-style Bootstrap theme) with leftover placeholder cruft never replaced with real
|
(SB Admin 2-style Bootstrap theme) with leftover placeholder cruft never replaced with real
|
||||||
content - e.g. `index.html`'s "Placeholder button", dropdown menus full of "Action" / "Another
|
content - e.g. `index.html`'s "Placeholder button", dropdown menus full of "Action" / "Another
|
||||||
action" / "Something else here" stub links, and a `/dtc` page that's just an empty "Output" card
|
action" / "Something else here" stub links, and a `/dtc` page that's just an empty "Output" card
|
||||||
with nothing wired up to it at all. Given how much is changing anyway (phone-relay removal,
|
with nothing wired up to it at all. Phase 14 already pulled the *foundational* piece of this
|
||||||
new dashcam/video browsers, richer OBD data), do a proper pass over the whole UI rather than
|
work forward (shared layout/list component, used by every phase since); this phase is the
|
||||||
keep bolting new cards onto the old template:
|
remaining cleanup once all the functional phases above have landed:
|
||||||
- Replace/remove all placeholder buttons, dropdown menus, and stub links that don't do anything.
|
- Replace/remove all remaining placeholder buttons, dropdown menus, and stub links that don't do
|
||||||
- Real design pass for the new features rather than reusing the generic admin-template card style
|
anything.
|
||||||
as-is: the dashcam/video file browsers (Phases 13-14) and the expanded OBD data (Phase 15) all
|
- Wire up the actually-empty `/dtc` page to show real DTC/MIL data from Phase 17.
|
||||||
need list/table and status-display patterns that don't really exist in the current template.
|
- Add the new dashboard cards for Phase 17's expanded OBD data (coolant temp, fuel level,
|
||||||
- Wire up the actually-empty `/dtc` page to show real DTC/MIL data once Phase 15 exposes it.
|
throttle) and Phase 19's Pi health card, using the Phase 14 component patterns.
|
||||||
- Not yet scoped: whether to keep Bootstrap 5 + the current theme framework and just clean it up,
|
- Final visual polish pass across every page now that the full feature set (dashcam/video
|
||||||
or replace the frontend stack entirely. To be decided once the functional phases above land, so
|
browsers, trip history, settings, alerts) exists, rather than redesigning against a moving
|
||||||
the redesign is done once against the final feature set rather than repeatedly against a moving
|
|
||||||
target.
|
target.
|
||||||
|
- Not yet scoped: whether to keep Bootstrap 5 + the current theme framework and just clean it up,
|
||||||
|
or replace the frontend stack entirely - decide once everything above has landed.
|
||||||
|
|
||||||
### Phase 17: Native Android companion app — 🚧 PLANNED (low priority, do last)
|
### Phase 23: Native Android companion app — 🚧 PLANNED (low priority, do last)
|
||||||
Revives the phone-relay goal (Phase 11/12) properly this time, using a real native app instead of
|
Revives the phone-relay goal (Phase 11/12) properly this time, using a real native app instead of
|
||||||
a web page - the only way to actually hold a WiFi connection to the Pi's hotspot and a cellular
|
a web page - the only way to actually hold a WiFi connection to the Pi's hotspot and a cellular
|
||||||
connection to the internet open simultaneously (`ConnectivityManager.bindProcessToNetwork()`,
|
connection to the internet open simultaneously (`ConnectivityManager.bindProcessToNetwork()`,
|
||||||
unavailable to browser JS - see the Phase 11 update). Explicitly **not urgent** - deprioritized to
|
unavailable to browser JS - see the Phase 11 update). Explicitly **not urgent** - deprioritized to
|
||||||
the end of the roadmap, after all web-side work (Phases 12-16) is done. Scope, at a high level
|
the end of the roadmap, after all web-side work (Phases 12-22) is done. Scope, at a high level
|
||||||
(not yet designed in detail):
|
(not yet designed in detail):
|
||||||
- **Dashcam file transfer**: browse/select/delete dashcam clips already imported to the Pi (same
|
- **Dashcam file transfer**: browse/select/delete dashcam clips already imported to the Pi (same
|
||||||
data as the Phase 14 local video browser, just a native client instead of/alongside the web UI),
|
data as the Phase 16 local video browser, just a native client instead of/alongside the web UI),
|
||||||
download them to the phone, and upload to the remote server over cellular while the phone stays
|
download them to the phone, and upload to the remote server over cellular while the phone stays
|
||||||
on the Pi's hotspot for the download leg - the true simultaneous dual-network relay the web
|
on the Pi's hotspot for the download leg - the true simultaneous dual-network relay the web
|
||||||
version could never deliver.
|
version could never deliver.
|
||||||
- **Trip/location info**: surface live GPS position, speed, and trip history pulled from the Pi
|
- **Trip/location info**: surface live GPS position, speed, and trip history (Phase 18) pulled
|
||||||
while connected to its hotspot (reusing the existing `/api/gps`-style data feeds), so the app is
|
from the Pi while connected to its hotspot (reusing the existing `/api/gps`-style data feeds),
|
||||||
useful as a real "check on the car" companion, not just a file-transfer tool.
|
so the app is useful as a real "check on the car" companion, not just a file-transfer tool.
|
||||||
- Not yet scoped: distribution (sideload vs Play Store), whether it talks to the Pi directly over
|
- Not yet scoped: distribution (sideload vs Play Store), whether it talks to the Pi directly over
|
||||||
the hotspot only or also to the remote server directly for trip history when away from the car,
|
the hotspot only or also to the remote server directly for trip history when away from the car,
|
||||||
and how much of the existing REST API surface can be reused as-is vs needs new
|
and how much of the existing REST API surface can be reused as-is vs needs new
|
||||||
mobile-friendly endpoints. To be designed once Phases 12-16 (web-side cleanup + hardening +
|
mobile-friendly endpoints. To be designed once Phases 12-22 (web-side cleanup + hardening +
|
||||||
redesign) are done.
|
redesign) are done.
|
||||||
|
|
||||||
## Working Notes / Environment Gotchas
|
## Working Notes / Environment Gotchas
|
||||||
|
|||||||
Reference in New Issue
Block a user