Redesign phase A: SQLite storage, per-frame data model, device identity
Replaces the single global config.json (whole-file pydantic model under one RLock) with SQLite via SQLAlchemy 2.0: users/sessions/frames/links/ pending-claims/battery_log tables (models.py), a per-frame lock registry (db.frame_locked) succeeding config.locked(), and hand-rolled schema versioning (migration.py). A pre-database deployment's config.json is imported verbatim as frame #1 on first boot and left untouched as the rollback path; the old single firmware.bin slot becomes per-frame firmware/<id>.bin. Routes split out of the 900-line main.py into routers/device.py (the frozen /frame/* protocol) and routers/api.py (web UI, still on the old single-frame paths for now). Device auth moves to require_device, which already speaks the full multi-frame protocol: per-frame device tokens pushed via /frame/config and acknowledged on first use, self- registration of unknown device ids as unclaimed frames, pending-claim attachment, and the legacy-token migration window that keeps the currently-deployed firmware (no id, shared MANAGEMENT_TOKEN) resolving to frame #1 -- including the one-time binding of its device id when it first reports one after a future OTA. Externally identical for existing deployments: same paths, same token semantics, same response shapes -- verified with a migration fixture, the legacy-device curl suite, a 20-way concurrent-advance smoke test, and a mutate-restart-assert persistence check against a fake Immich. photo_queue.py ports nearly verbatim onto the Frame ORM row (MutableList JSON columns make its in-place list mutations dirty-track); quiet-hours math extracted unchanged into quiet_hours.py.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
"""Local firmware image storage + esp_app_desc_t parsing. Shared by the
|
||||
manual upload path (POST /api/firmware) and the Gitea auto-update path
|
||||
(see gitea_releases.py) -- both end up writing the same firmware.bin slot
|
||||
that GET /frame/firmware streams to the device."""
|
||||
"""Per-frame firmware image storage + esp_app_desc_t parsing. Shared by
|
||||
the manual upload path and the Gitea auto-update path -- both end up
|
||||
writing the same per-frame slot that GET /frame/firmware streams to the
|
||||
device. The migration moves the old single /data/firmware.bin into frame
|
||||
#1's slot."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -18,8 +19,8 @@ APP_DESC_MAGIC = 0xABCD5432
|
||||
EXPECTED_PROJECT_NAME = "espresso_frame"
|
||||
|
||||
|
||||
def firmware_path():
|
||||
return config.CONFIG_PATH.parent / "firmware.bin"
|
||||
def firmware_path(frame_id: int):
|
||||
return config.CONFIG_PATH.parent / "firmware" / f"{frame_id}.bin"
|
||||
|
||||
|
||||
def parse_app_version(data: bytes) -> str:
|
||||
|
||||
Reference in New Issue
Block a user