Related
- Device RPC — persistent RPC, the delivery mechanism behind OTA.
- Device profiles — the rollout target and the OTA policy a device inherits.
- Credential rotation — keep device credentials healthy across firmware generations.
OTA (over-the-air) updates push new firmware or software to a fleet without touching the hardware. CORE-M models this in two parts: an OTA package (the verified artifact and its metadata) and a rollout (the staged campaign that delivers it to a set of devices). Delivery rides on persistent RPC, so an update reaches a device whenever it next connects, and the device reports the result back.
This is an operator how-to. You’ll upload a package, start a canary rollout, watch it, and roll back if it goes wrong.
A package is the artifact plus the metadata CORE-M needs to verify it, decide compatibility, and present it to devices.
| Field | Meaning |
|---|---|
version | Semantic version of the build, e.g. 2.0.0. |
artifact_uri | Where the binary lives. |
sha256 | Declared checksum of the artifact. Verified before the package is usable. |
signature | Cryptographic signature of the artifact. |
size_bytes | Artifact size, so devices can plan the download. |
compatibility | Which device types / hardware the build may target. |
release_notes | Human-readable change summary. |
type | fw (firmware) or sw (software). |
When you upload a package, CORE-M downloads the artifact and verifies its checksum
against the declared sha256 before the package becomes available to any
rollout. If the computed checksum doesn’t match, the package is rejected with
INVALID_ARGUMENT and is never assigned anywhere. Devices independently verify
the signature and checksum after download, so a corrupted transfer is caught on
both ends.
curl -X POST https://api.kronoxdata.com/api/v1/ota/packages \ -H "Authorization: Bearer <tenant-admin-jwt>" \ -H "Content-Type: application/json" \ -d '{ "type": "fw", "version": "2.0.0", "artifact_uri": "s3://ota-artifacts/temp-sensor/fw-2.0.0.bin", "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "signature": "MEUCIQD...", "size_bytes": 524288, "compatibility": { "device_type": "temp-sensor", "min_version": "1.0.0" }, "release_notes": "Fix sensor drift above 60C; reduce idle current." }'{ "package_id": "pkg_2a0f", "status": "available", "checksum_verified": true}A rollout delivers one package to a target set of devices, in stages, with safety controls. You target a device profile, start with a small canary percentage, and let CORE-M expand the rollout only if the canary is healthy.
stateDiagram-v2 [*] --> active : start (canary %) active --> paused : operator pause active --> paused : failure threshold exceeded\n(auto, alert) paused --> active : resume active --> rolling_back : operator rollback paused --> rolling_back : operator rollback active --> completed : all target devices successful rolling_back --> completed : rollback finished completed --> [*]
Per device, each target tracks its own state: scheduled → (update command sent)
→ successful or failure, surfaced as Device RPC records.
Start the rollout. Target a profile, point at the verified package, and set a small canary percentage and a failure threshold. Only the canary slice gets the command first.
curl -X POST https://api.kronoxdata.com/api/v1/ota/rollouts \ -H "Authorization: Bearer <tenant-admin-jwt>" \ -H "Content-Type: application/json" \ -d '{ "package_id": "pkg_2a0f", "target_profile_id": "prof_temp_v2", "canary_percent": 5, "failure_threshold_percent": 10, "rollback_package_id": "pkg_19b3" }'{ "rollout_id": "rol_4c7e", "status": "active", "canary_percent": 5, "scheduled_count": 12}Only 5% of eligible devices are scheduled initially; the rest wait. Event
profile.ota.rollout.started.{tenant}.{rollout_id} is published.
Updates are delivered via persistent RPC. CORE-M issues an ota_start
command (a persistent RPC) to each scheduled device. Because it’s persistent,
a device that’s offline receives it on reconnect. The device downloads the
artifact (resumable, in chunks), verifies signature and checksum, applies it,
and reboots.
Devices report results. Each device reports back its firmware_version and
success/failure. On success its rollout state becomes successful, its
device firmware field updates to the new version, and the rollout’s success
counters advance.
{ "device_id": "dev_8f3a", "rollout_id": "rol_4c7e", "firmware_version": "2.0.0", "status": "success"}Watch the canary, then expand. If the canary stays healthy, advance the rollout to the rest of the fleet (resume / raise canary). If it doesn’t, the failure threshold steps in — see below.
You can pause a rollout at any time, and CORE-M pauses it automatically if
failures cross the threshold. With failure_threshold_percent=10, once 11% of
canary devices report failure the rollout monitor flips the rollout to paused,
schedules no further devices, and publishes alert event
profile.ota.rollout.paused.{tenant}.{rollout_id}.
curl -X POST https://api.kronoxdata.com/api/v1/ota/rollouts/rol_4c7e/pause \ -H "Authorization: Bearer <tenant-admin-jwt>"Once you’ve diagnosed a pause (or simply want to continue a manual hold), resume. Scheduling picks back up from where it stopped.
curl -X POST https://api.kronoxdata.com/api/v1/ota/rollouts/rol_4c7e/resume \ -H "Authorization: Bearer <tenant-admin-jwt>"When the new build is bad, roll back to the configured rollback_package_id.
CORE-M sends rollback commands to affected devices, sets the rollout to
rolling_back, and tracks every command through Device RPC records — so you get
the same per-device visibility on the way down as on the way up.
curl -X POST https://api.kronoxdata.com/api/v1/ota/rollouts/rol_4c7e/rollback \ -H "Authorization: Bearer <tenant-admin-jwt>"A device under a rollout learns about its assigned package and pulls the bytes itself:
GET /api/v1/devices/{device_id}/ota returns the package metadata
(package_id, type, version, size_bytes, checksum) for the
authenticated device — device-level assignment beats profile-level.GET /api/v1/devices/{device_id}/ota/chunk streams the artifact as byte ranges
(clamped to 64 KiB per chunk), in any order, so downloads are resumable over
flaky links. A device may only fetch its own assigned package; any other
package_id returns PermissionDenied.The device verifies the checksum (and signature) once the last chunk arrives
(complete: true) before applying the update.
Related