Add local settings management

Add cellular-first ntfy delivery with WiFi fallback and safe SIM868 HTTP header framing.

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-09 21:26:15 -04:00
co-authored by Copilot
parent b77ed838bd
commit 3a6f12ba9d
15 changed files with 1118 additions and 103 deletions
+51 -4
View File
@@ -1053,7 +1053,7 @@ that could contain a private topic URL.
badge counts, alert titles/details, no-alert state, synthetic monitor-failure state, shared-shell
availability, and no-horizontal-overflow behavior passed with no new console errors.
### Phase 21: Settings page — 🚧 PLANNED
### Phase 21: Settings page — ✅ DONE
**New phase - depends on Phase 15's shared components, and benefits from Phases 17/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`,
@@ -1064,6 +1064,34 @@ upload toggle, cellular APN, local video retention policy, alert webhook URL + t
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.
**Implemented and hardware-tested 2026-08-09.** Added a dedicated local `/settings` page and
validated `/api/settings` endpoint backed by the existing SQLite settings table. It consolidates
the dashcam-upload toggle, uploaded-video retention days, SIM868 cellular enable/APN, optional
ntfy enable/URL/token, and alert temperature/disk/backlog/GPS-loss/repeat thresholds. Updates are
validated as a complete group and committed atomically; invalid requests leave the prior
configuration untouched. Cellular enable/APN reads persisted settings live, so those changes do
not need an app restart. Sensitive ntfy URL/token values are write-only through the API: the page
only reports whether each is configured and supports explicit removal, so saved secrets are never
sent back to browser JavaScript. Local Web UI alerts remain active independently of ntfy.
When cellular is configured, ntfy delivery now uses the SIM868's small-body HTTP client as the
primary transport with the notification title, priority, tags, and optional bearer token.
WiFi/Ethernet is the fallback if the modem path fails. The generalized modem POST path rejects
quotes/newlines in AT-command parameters before touching hardware. This is mock/Pi-code tested but
remains explicitly unverified over a real carrier until a SIM is available; Phase 24 must prove
authenticated HTTPS, fallback, retry, and recovery behavior or remove ntfy entirely if the SIM868
cannot deliver it reliably.
Moved the dashcam-upload control from `/dash` into Settings rather than keeping duplicate controls,
while retaining pending-row, last-success/path, and last-error upload health in the new page.
WiFi credentials, remote-server device/API credentials, cellular username/password, and other
lockout/high-risk configuration remain file/SSH managed by design. Focused settings/alert tests
pass locally and on the Pi; the real Pi rejected an invalid update with HTTP 400 while preserving
its exact configuration. The live page loaded through `yaris.local` with the Pi's existing
defaults and shared alert/navigation shell. Browser testing at 390x844 found and fixed an initial
top-bar overlap by adding a dedicated bottom mobile save action; the real save then completed with
no horizontal overflow or console errors.
### Phase 22: Finish web UI redesign — 🚧 PLANNED
**Roadmap decision 2026-08-09: keep this as Phase 22 rather than moving it forward.** Phase 15
already pulled the architecture-level work forward: every page now shares one Jinja shell and
@@ -1131,6 +1159,18 @@ recorded trip details, and footage can be accessed away from the car:
HTML/JavaScript.
- Support selecting a vehicle/device if more than one is registered later, while defaulting
cleanly to the current Yaris. Keep trip APIs scoped to the authenticated user/device.
- Synchronize alert transitions, recoveries, timestamps, severity/details, and current state from
the Pi to the server through an authenticated, idempotent offline queue. The Pi remains
authoritative for vehicle/hardware detection and its local bell must never depend on internet
access. The server stores per-vehicle alert history/current state, reconciles reconnects without
duplicates, and exposes it in the remote portal; remote acknowledgement must not silently clear
the underlying Pi condition.
- Synchronize alert transitions, recoveries, timestamps, severity/details, and current state from
the Pi to the server through an authenticated, idempotent offline queue. The Pi remains
authoritative for vehicle/hardware detection and its local bell must never depend on internet
access. The server stores per-vehicle alert history/current state, reconciles reconnects without
duplicates, and exposes it in the remote portal; remote acknowledgement must not silently clear
the underlying Pi condition.
- Deploy only after Phase 22 is complete: rebuild the unraid Docker stack, verify migrations against
copied data first, compare remote trip calculations with uploaded Pi records, verify playback,
Range requests, and downloads against disposable copies of real server footage, and browser-test
@@ -1187,8 +1227,13 @@ clean trip end:
returns to recording afterward. Test deletion only with the disposable clip.
- **Alerts:** safely exercise conditions that can be simulated without damaging hardware (upload
backlog, temporary GPS loss while OBD reports motion, and disposable threshold overrides).
Confirm local bell transition/recovery/cooldown behavior. Do not intentionally overheat,
undervolt, fill storage, or trigger a real MIL. Verify ntfy only if it has been configured by then.
Confirm local bell transition/recovery/cooldown behavior and offline alert-state reconciliation
with the Phase 23 server after connectivity returns. Do not intentionally overheat, undervolt,
fill storage, or trigger a real MIL. With a real SIM, explicitly determine whether the SIM868
transport can reliably deliver ntfy notifications while WiFi/Ethernet is unavailable, including
authentication, timeout, retry, and recovery. If that cannot be made reliable on the actual
modem/network, remove the ntfy feature and its settings rather than retain a transport that fails
in the only situation where it is useful.
- **Power/reliability:** perform multiple normal ignition/power cycles, confirm automatic boot,
service/watchdog startup, SIM868 power-on, OBD/GPS recovery, no SQLite corruption, and no current
undervoltage/throttling. The deferred Phase 14 clean-shutdown limitation must be explicitly
@@ -1201,7 +1246,9 @@ Verify the complete remote path after connectivity returns:
remotely.
- On the Phase 23 portal, verify the explicit **Remote server** identity, authenticated
vehicle-scoped trip summary/replay, route and timeline agreement with the local Pi, archived clip
thumbnail/playback/Range seeking/download, and absence of local-only OBD/cellular/Pi controls.
thumbnail/playback/Range seeking/download, synchronized alert history/current state without
duplicate transitions after an offline interval, and absence of local-only OBD/cellular/Pi
controls.
- The Android companion is intentionally outside this core acceptance gate and remains the final,
low-priority Phase 25. Its own hotspot/cellular binding, trip display, and disposable clip relay
require separate real-phone/in-car acceptance when that phase is implemented.