Consolidate firmware UI; server learns board from the device, not a picker
Build and push server image / build-and-push (push) Successful in 37s
Build and push server image / build-and-push (push) Successful in 37s
All firmware-related controls (manual upload, Gitea repo URL, auto-update checkbox, detected board, Update frame button) now live in one "Firmware update" card instead of being split across the main Settings form and a separate card. The board variant used to pick a Gitea release asset was a dropdown the user had to set by hand and could get wrong. The device now reports it itself via a new X-Frame-Board header (CONFIG_FRAME_BOARD_NAME, "devkit" by default, "xiao" in sdkconfig.xiao) on every /frame/config poll, stored as device_board_variant -- the server learns it instead. Update checks/applies are gated on the board being known, since there's nothing to fetch until a device has checked in at least once.
This commit is contained in:
+28
-17
@@ -48,14 +48,17 @@ algorithm itself -- it just streams the response straight to the panel.
|
||||
pushing this repo to a Gitea instance, `.gitea/workflows/firmware-release-build.yml`
|
||||
builds both supported boards and publishes them as release assets
|
||||
(`firmware-xiao.bin`/`firmware-devkit.bin`) whenever `firmware/version.txt`
|
||||
changes on `main`. In the web UI's Settings form, set **Firmware Gitea
|
||||
repo URL** to that repo (e.g. `https://git.example.com/owner/repo`) and
|
||||
pick the frame's **board**; if the repo is private, also set
|
||||
`GITEA_FIRMWARE_TOKEN` (a read-only PAT) in `docker-compose.yml`. The
|
||||
server then periodically checks for a newer release and either shows
|
||||
an "Update frame" button or, with **Automatically apply updates**
|
||||
checked, stages it itself -- either way the frame only actually
|
||||
updates on its own next wake (see `POST /api/firmware` above).
|
||||
changes on `main`. In the web UI's "Firmware update" card, set the
|
||||
**Gitea repo URL** to that repo (e.g. `https://git.example.com/owner/repo`);
|
||||
if the repo is private, also set `GITEA_FIRMWARE_TOKEN` (a read-only
|
||||
PAT) in `docker-compose.yml`. Which board's build to fetch is learned
|
||||
from the frame itself (its `X-Frame-Board` header, `CONFIG_FRAME_BOARD_NAME`
|
||||
on the firmware side) -- nothing to pick by hand, though the frame
|
||||
does need to have checked in at least once first. The server then
|
||||
periodically checks for a newer release and either shows an "Update
|
||||
frame" button or, with **Automatically apply updates** checked,
|
||||
stages it itself -- either way the frame only actually updates on its
|
||||
own next wake (see `POST /api/firmware` above).
|
||||
|
||||
## Endpoints
|
||||
|
||||
@@ -117,7 +120,11 @@ algorithm itself -- it just streams the response straight to the panel.
|
||||
device compares it against its own running version
|
||||
(`esp_app_get_description()->version`, sent as an `X-Frame-Version`
|
||||
request header, stored as `device_firmware_version`) to decide whether
|
||||
to OTA
|
||||
to OTA. The device also sends an `X-Frame-Board` header
|
||||
(`CONFIG_FRAME_BOARD_NAME`, e.g. `"xiao"`), stored as
|
||||
`device_board_variant` -- how the Gitea auto-update feature below
|
||||
learns which board to fetch a release for, instead of a user picking
|
||||
it
|
||||
- `GET /frame/photo-info` -- `{"asset_id": ..., "location_line1": ... |
|
||||
null, "location_line2": ... | null, "taken_at": ... | null}` for the
|
||||
current photo (same idempotent current-photo semantics as
|
||||
@@ -170,16 +177,20 @@ algorithm itself -- it just streams the response straight to the panel.
|
||||
been uploaded yet
|
||||
- `GET /api/firmware/check` -- throttled (`gitea_releases.UPDATE_CHECK_INTERVAL_S`,
|
||||
15 min) check of the configured Gitea repo's latest release for the
|
||||
frame's board variant. `{"enabled": false}` if no repo URL is
|
||||
configured; otherwise `{"enabled": true, "latest_version": "1.2.3" | null,
|
||||
"staged_version": "1.2.2" | null, "update_available": bool}`. If
|
||||
"Automatically apply updates" is on and a newer release is found, this
|
||||
call also stages it immediately (same effect as a manual upload) --
|
||||
otherwise the web UI shows an "Update frame" button
|
||||
frame's board variant (learned from the device, see `device_board_variant`
|
||||
below -- not user-configured). `{"enabled": false}` if no repo URL is
|
||||
configured; otherwise `{"enabled": true, "board": "xiao" | null,
|
||||
"latest_version": "1.2.3" | null, "staged_version": "1.2.2" | null,
|
||||
"update_available": bool}`. `update_available` stays false until the
|
||||
board is known, regardless of what Gitea has. If "Automatically apply
|
||||
updates" is on and a newer release is found, this call also stages it
|
||||
immediately (same effect as a manual upload) -- otherwise the web UI
|
||||
shows an "Update frame" button
|
||||
- `POST /api/firmware/apply-latest` -- the "Update frame" button: pulls
|
||||
and stages the latest Gitea release right now, bypassing the check
|
||||
throttle. 404 if no repo is configured, has no releases, or the latest
|
||||
release has no asset for the configured board variant
|
||||
throttle. 400 if no repo is configured or no device has checked in
|
||||
yet (board unknown); 404 if the repo has no releases, or the latest
|
||||
release has no asset for the frame's board
|
||||
- `GET /api/queue` -- `{"current": {...} | null, "upcoming": [...],
|
||||
"device": {"last_seen": ts | null, "overdue": bool,
|
||||
"firmware_version": "1.2.3" | null, "firmware_available": "1.2.4" | null,
|
||||
|
||||
Reference in New Issue
Block a user