Add two physical buttons: factory-reset and next-photo
Build and push server image / build-and-push (push) Successful in 35s

Factory-reset (GPIO3, hold 10s): clears stored WiFi/server config and
restarts into provisioning -- the deliberate, USB-free replacement for
the earlier reverted RST-based auto-reprovisioning idea.

Next-photo (GPIO2, tap): wakes the device and forces the server to
advance immediately via a new POST /frame/advance, instead of waiting
for the refresh interval. Both buttons arm themselves as deep-sleep GPIO
wakeup sources so a press is noticed promptly even while asleep.

Also makes GET /frame/image side-effect-free: it now only advances once
refresh_interval_s has elapsed since the current photo was set (tracked
server-side), so a device reboot for any reason just redisplays the
current photo instead of silently skipping ahead. The server maintains a
small reorderable upcoming-photos queue, viewable and rearrangeable from
the web UI.
This commit is contained in:
2026-07-18 23:28:36 -04:00
parent 7013311249
commit d395cf3bb9
19 changed files with 668 additions and 47 deletions
+8 -1
View File
@@ -20,10 +20,17 @@ class FrameConfig(BaseModel):
immich_api_key: str = ""
album_id: str = ""
order: str = "sequential" # or "shuffle"
cursor: int = 0
refresh_interval_s: int = 3600
smart_crop_faces: bool = True
# Current photo + upcoming queue (see app/photo_queue.py). current_asset_set_at
# is what lets the server decide "has it been long enough to advance" on its
# own clock, independent of how/why the device asked for a photo.
current_asset_id: str = ""
current_asset_set_at: float = 0.0
queue: list[str] = []
queue_cursor: int = 0 # internal bookkeeping for sequential queue top-up; not user-facing
def load() -> FrameConfig:
with _lock: