Skip to content

feat(firmware,sensing-server): pull-based OTA — client + registry#488

Open
schwarztim wants to merge 2 commits intoruvnet:mainfrom
schwarztim:pr/firmware-pull-ota
Open

feat(firmware,sensing-server): pull-based OTA — client + registry#488
schwarztim wants to merge 2 commits intoruvnet:mainfrom
schwarztim:pr/firmware-pull-ota

Conversation

@schwarztim
Copy link
Copy Markdown

@schwarztim schwarztim commented Apr 28, 2026

Summary

  • ESP32 OTA pull client (firmware/esp32-csi-node/main/ota_pull.c, +412 LOC): sensing nodes poll GET /api/v1/firmware/latest every 5 min, download + SHA-256 verify a newer binary via GET /api/v1/firmware/download, write it to the ESP-IDF OTA partition, and restart. Includes BLE stop guard, 5-min uptime gate before first check, and relies on the existing ota_update.c canary task for ESP-IDF rollback.
  • Server firmware registry (v2/crates/wifi-densepose-sensing-server/src/firmware_registry.rs, +452 LOC): pure-Rust, transport-agnostic in-memory registry with SHA-256 integrity, sidecar manifest support, version parsing from filename, and 11 unit tests.
  • Three HTTP endpoints wired into main.rs: GET /api/v1/firmware/latest, GET /api/v1/firmware/download, POST /api/v1/firmware/upload?version=X.
  • ADR-095 (docs/adr/ADR-095-pull-based-ota.md): design record documenting the pull model, architecture, and tradeoffs.
  • CHANGELOG updated under [Unreleased].

Motivation

Push-based OTA requires operators to enumerate every node IP. Nodes that come online intermittently or are behind NAT/CGNAT get missed entirely. The pull model has zero operator action for routine upgrades — nodes catch up on their next poll cycle regardless of network topology.

Files changed

Path Change
firmware/esp32-csi-node/main/ota_pull.c New — 412-LOC OTA pull task
firmware/esp32-csi-node/main/ota_pull.h New — header
firmware/esp32-csi-node/main/CMakeLists.txt Add ota_pull.c to SRCS
firmware/esp32-csi-node/main/main.c Wire ota_pull_init() on network-up path
v2/crates/wifi-densepose-sensing-server/src/firmware_registry.rs New — Rust registry + 11 tests
v2/crates/wifi-densepose-sensing-server/src/main.rs Wire 3 endpoints + AppStateInner fields
v2/crates/wifi-densepose-sensing-server/Cargo.toml Add sha2, thiserror deps
docs/adr/ADR-095-pull-based-ota.md New ADR
CHANGELOG.md Unreleased entry

Test plan

  • cargo test --workspace --no-default-features — 1642 tests pass (includes 11 firmware_registry unit tests)
  • Firmware builds with CONFIG_CSI_MOCK_ENABLED=n (real WiFi mode) — ota_pull.c compiles without heartbeat.h dep
  • GET /api/v1/firmware/latest with no firmware staged returns {"available":false}
  • Upload a test binary → latest returns {"available":true, "version":"...", "sha256":"..."} → download and verify SHA-256 matches
  • ESP32 node with older esp_app_desc.version polls and self-upgrades; node with matching version skips

Deploy Bot added 2 commits April 28, 2026 14:08
ESP32 nodes poll GET /api/v1/firmware/latest and self-upgrade when the
server advertises a newer version. SHA-256 verified; ESP-IDF rollback
failsafe reverts on crash in the first boot window.

Server side: new firmware_registry module (in-memory manifest holder,
set_current, is_update_available, sha256_bytes/sha256_file helpers,
11 unit tests). Three HTTP endpoints wired into sensing-server:
  GET  /api/v1/firmware/latest
  GET  /api/v1/firmware/download
  POST /api/v1/firmware/upload?version=X[&sha256=HEX]
Startup scan of --firmware-dir seeds the registry from the newest .bin.

Firmware client (ota_pull.c, +413 LOC): polling task, SHA-256 verify,
OTA partition write, BLE stop guard, uptime guard, graceful retry on error.

Includes ADR-094 design record and CHANGELOG entry.
…racking PR

PR ruvnet#487 (body tracking platform) was filed first and claims ADR-094.
Rename docs/adr/ADR-094-pull-based-ota.md → ADR-095-pull-based-ota.md
and update all references in CHANGELOG.md, Cargo.toml, and main.rs comments.
@schwarztim
Copy link
Copy Markdown
Author

Renumbered the ADR from 094 to 095 to avoid collision with PR #487 (body tracking platform), which was filed first. Force-pushed an updated commit with the rename: docs/adr/ADR-094-pull-based-ota.md → ADR-095-pull-based-ota.md, plus all comment references in main.rs and Cargo.toml updated.

@schwarztim schwarztim changed the title feat(firmware,sensing-server): pull-based OTA — client + registry (ADR-094) feat(firmware,sensing-server): pull-based OTA — client + registry Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant