Fix WiFi boot, background polling, state ring, and device-server proxy #2

Merged
speedi57 merged 5 commits from fix/wifi-connect-background-poll into main 2026-10-18 12:46:12 +00:00
Owner

Summary

 setup()
-  (no WiFi start: wifi_mgr::begin() was dropped in 07f621a)
+  ota_updater::begin()
   app_init()                       # screen up first
+  wifi_mgr::begin(20000)

 loop()                             # UI thread only: never blocks on network
   touch_read
   lock: input_handle + render_frame (+ state ring)
   update_brightness                # dim 60s / near-off 5min

+poll_task (core 0, priority 0)     # all blocking network I/O
+  OTA check/apply/maintain
+  poll_remote
+    fetch_device  GET /api/device  # new, ~1 KB
+    else fetch_profiles + fetch_health
Hermes (/health, /api/profiles, /api/sessions?all_profiles=1)
   │  localhost, every 3s
   ▼
server/  hermes-device-server (Rust, axum)
   │  GET /api/device  → 880 B JSON, per-profile "running"
   ▼
ESP32 screen
  • Restore the WiFi connect that was removed in 07f621a.
  • Move Hermes polling and OTA off the UI thread (FreeRTOS task + mutex, thread-safe ota_updater::snapshot()).
  • Agent state ring (idle / busy / done / error / offline) and idle dimming.
  • New server/ crate: collapses three Hermes calls (369 KB / 2.1 MB for sessions) into one compact payload. running is true when one of the profile's sessions is streaming. Firmware falls back to the old two requests if /api/device is missing.
  • Forgejo workflow server.yml: fmt, clippy, tests; release artifact on server-v* tags.
  • manifest.json bumped to 0.6.6.

Evidence

  • Before: module never connected (no WiFi.begin). Once connected, the UI froze on every poll:
    [dbg] poll_remote took 3727 ms
    [dbg] loop gap 3781 ms        # every 10s
    
    A first background-task attempt (priority 1) reset the board via task watchdog (~25s). Profile status only reflected is_active (the default profile).
    After: connects ([wifi] connected, IP=192.168.1.7), no loop gaps from polling, 3 min serial run with no watchdog or reboot. cargo fmt --check, cargo clippy -D warnings, cargo test (2 tests) pass; cargo build --release --locked ok. Live against Hermes: /api/device is 880 B and returns "name":"developerheavy" ... "running":true while a run is active.

Not verified: the ring and dimming visually on the device, and the new firmware reading /api/device (server is not deployed yet; the fallback path is what runs today). The new workflow has not run on Forgejo yet.

Merge Danger

Door: two-way

Revert is cheap in git. Firmware only reaches devices if a v* tag is pushed (OTA publish), and the server only runs once deployed by hand.

Blast Radius: device

Tagging a release after merge ships the new firmware to the screen via OTA. The server crate and server.yml only run on server/** changes or server-v* tags and do not affect build.yml. OTA_DISABLE_SHA_CHECK is local config and is not part of this PR.

## Summary ```diff setup() - (no WiFi start: wifi_mgr::begin() was dropped in 07f621a) + ota_updater::begin() app_init() # screen up first + wifi_mgr::begin(20000) loop() # UI thread only: never blocks on network touch_read lock: input_handle + render_frame (+ state ring) update_brightness # dim 60s / near-off 5min +poll_task (core 0, priority 0) # all blocking network I/O + OTA check/apply/maintain + poll_remote + fetch_device GET /api/device # new, ~1 KB + else fetch_profiles + fetch_health ``` ```text Hermes (/health, /api/profiles, /api/sessions?all_profiles=1) │ localhost, every 3s ▼ server/ hermes-device-server (Rust, axum) │ GET /api/device → 880 B JSON, per-profile "running" ▼ ESP32 screen ``` - Restore the WiFi connect that was removed in `07f621a`. - Move Hermes polling and OTA off the UI thread (FreeRTOS task + mutex, thread-safe `ota_updater::snapshot()`). - Agent state ring (idle / busy / done / error / offline) and idle dimming. - New `server/` crate: collapses three Hermes calls (369 KB / 2.1 MB for sessions) into one compact payload. `running` is true when one of the profile's sessions is streaming. Firmware falls back to the old two requests if `/api/device` is missing. - Forgejo workflow `server.yml`: fmt, clippy, tests; release artifact on `server-v*` tags. - `manifest.json` bumped to 0.6.6. ## Evidence - **Before:** module never connected (no `WiFi.begin`). Once connected, the UI froze on every poll: ```text [dbg] poll_remote took 3727 ms [dbg] loop gap 3781 ms # every 10s ``` A first background-task attempt (priority 1) reset the board via task watchdog (~25s). Profile status only reflected `is_active` (the default profile). **After:** connects (`[wifi] connected, IP=192.168.1.7`), no loop gaps from polling, 3 min serial run with no watchdog or reboot. `cargo fmt --check`, `cargo clippy -D warnings`, `cargo test` (2 tests) pass; `cargo build --release --locked` ok. Live against Hermes: `/api/device` is 880 B and returns `"name":"developerheavy" ... "running":true` while a run is active. Not verified: the ring and dimming visually on the device, and the new firmware reading `/api/device` (server is not deployed yet; the fallback path is what runs today). The new workflow has not run on Forgejo yet. ## Merge Danger **Door:** two-way Revert is cheap in git. Firmware only reaches devices if a `v*` tag is pushed (OTA publish), and the server only runs once deployed by hand. **Blast Radius:** device Tagging a release after merge ships the new firmware to the screen via OTA. The server crate and `server.yml` only run on `server/**` changes or `server-v*` tags and do not affect `build.yml`. `OTA_DISABLE_SHA_CHECK` is local config and is not part of this PR.
wifi_mgr::begin() was dropped in 07f621a, so WiFi was never started.
Connect after display init, and move the blocking HTTPS polling off the
UI thread (FreeRTOS task + mutex) to stop ~3.7s freezes every 10s.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Polls Hermes health/profiles/sessions and serves one ~1KB JSON at
/api/device, including per-profile running state (streaming sessions).

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
- Agent state ring (idle/busy/done/error/offline) on every screen
- Dim after 60s idle, near-off after 5min; input or run events wake
- Run OTA checks/apply in the network task; thread-safe OTA snapshot()
- Run the network task at priority 0 to stop the task watchdog resets
- Read /api/device (falls back to /health + /api/profiles) and use the
  per-profile running flag for the profile status

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
ci(server): add Forgejo workflow for hermes-device-server
All checks were successful
server / Check (fmt, clippy, tests) (pull_request) Successful in 1m50s
server / Build release binary (tags server-v* only) (pull_request) Has been skipped
9d9efe465f
fmt, clippy (-D warnings) and tests on pushes/PRs touching server/;
release build + artifact on server-v* tags (must match Cargo.toml version
and be on main). Also applies cargo fmt.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thidev/hermes-compagnon!2
No description provided.