The update protocol
Agent packages and custom firmware fetch updates with two HTTPS calls: one to ask whether there is anything, one to download it. Any HTTP client can implement it, in any language, on any stack. It is what Connhex Edge does under the hood, and what you write yourself on a microcontroller or your own stack.
System image updates work differently. SWUpdate and RAUC speak the hawkBit DDI protocol on an endpoint of their own, and nothing on this page applies to them.
On an Enterprise instance, replace connhex.com with your domain.
Where to poll
A device that enrolled polls over mutual TLS with the certificate it already holds. The certificate identifies the device, so there is no id in the path and no credential in a header:
HEAD /things/ota HTTP/1.1
Host: edge.connhex.com
Version: 1.4.0
Use this endpoint for native OTA updates. The same certificate authenticates the device to the broker, configuration API, and update endpoint.
The Version header is how the device says what it is running. Send valid semver. Without it, the server has nothing to compare against and will offer the current release even if the device is already on it.
Checking for an update
curl -I --cert /data/connhex/client.crt \
--key /data/connhex/device.key \
-H "Version: 1.4.0" \
https://edge.connhex.com/things/ota
The client certificate identifies the device. curl uses the normal system CA bundle to verify the Connhex endpoint.
| Response | Meaning |
|---|---|
200 | There is an update. The headers describe it |
404 | Nothing for this device. Already current, or nothing has been published for it |
A 200 carries:
| Header | Meaning |
|---|---|
Version | The version being offered |
Content-Length | Size in bytes |
Content-Digest | sha256=<hex> of the file |
Content-Disposition | The file name |
Min-Version, Max-Version | Present when the release sets them |
ETag | The offered version, quoted |
Accept-Ranges | bytes |
Read everything you need from this response. It is the only place the metadata appears.
Downloading
curl --cert /data/connhex/client.crt \
--key /data/connhex/device.key \
-H "Version: 1.4.0" \
-o firmware.bin \
https://edge.connhex.com/things/ota
GET on the same URL returns the file. Add Range to fetch it in pieces:
curl --cert /data/connhex/client.crt \
--key /data/connhex/device.key \
-H "Range: bytes=0-1023" \
-o part1.bin \
https://edge.connhex.com/things/ota
Ranges are zero-based and the end is inclusive. Omitting the end still needs the dash, as in bytes=524288-.
| Response | Meaning |
|---|---|
200 | The whole file |
206 | The requested range |
416 | The range is out of bounds |
404 | Nothing for this device |
Resuming
To continue an interrupted download, send If-Range with the ETag you got earlier alongside your Range:
curl --cert /data/connhex/client.crt \
--key /data/connhex/device.key \
-H "Range: bytes=524288-" \
-H 'If-Range: "1.5.0"' \
-o rest.bin \
https://edge.connhex.com/things/ota
If the offered release is still the same, you get 206 and the remaining bytes. If it changed while you were away, you get 200 and the whole new file.
Verifying
Check the file against Content-Digest before installing anything:
sha256sum firmware.bin
#!/bin/sh
set -e
URL="https://edge.connhex.com/things/ota"
CERT="/data/connhex/client.crt"
KEY="/data/connhex/device.key"
digest=$(curl -sS --cert "$CERT" --key "$KEY" -D - -o firmware.bin \
-H "Version: $CURRENT" "$URL" \
| awk 'tolower($1) == "content-digest:" {print $2}' | tr -d '\r')
case "$digest" in
sha256=*) expected=${digest#sha256=} ;;
*) echo "unexpected digest format: $digest" >&2; exit 1 ;;
esac
actual=$(sha256sum firmware.bin | cut -d' ' -f1)
[ "$expected" = "$actual" ] || { echo "checksum mismatch" >&2; exit 1; }
echo "verified $expected"
How progress is reported
The version your device sends on its next poll is what tells Connhex the update worked. A device that comes back on the target version is recorded as updated, one that comes back on the old version is offered the update again, and after long enough without progress the attempt is recorded as failed.
That makes the Version header the one thing worth getting right. It is your device's only voice in the campaign monitor.
Polling cadence
Poll every 15 minutes or more, plus a check whenever the device reconnects. Spread a large fleet with a little jitter, so a site coming back after a power cut does not arrive all at once. Sustained polling beyond a modest burst is throttled, so back off when a request is refused instead of retrying immediately.