Skip to content

OTA updates

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.

FieldMeaning
versionSemantic version of the build, e.g. 2.0.0.
artifact_uriWhere the binary lives.
sha256Declared checksum of the artifact. Verified before the package is usable.
signatureCryptographic signature of the artifact.
size_bytesArtifact size, so devices can plan the download.
compatibilityWhich device types / hardware the build may target.
release_notesHuman-readable change summary.
typefw (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.

Terminal window
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.

  1. 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.

    Terminal window
    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.

  2. 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.

  3. 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"
    }
  4. 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}.

Terminal window
curl -X POST https://api.kronoxdata.com/api/v1/ota/rollouts/rol_4c7e/pause \
-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

  • 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.