OTA Firmware update
Connhex is dedicated to hardware manufacturers: their firmware update strategies, albeit with some commonalities, vary a lot. This is why, for the time being, Connhex offers basic support for OTA updates: you can contact us to see how your current firmware update process fits with Connhex.
As of today, Connhex only supports user-space software updates.
Pull update strategy
Broadly speaking, IoT firmware updates can be separated in:
- push updates: updates are split into chunks, then sent to the device - typically as MQTT(s) packets, if the protocol is available. The device then recreates the entire update, checks its integrity and applies it.
- pull updates: the device requests for available updates. If at least one is present, it is obtained as a file download through the HTTP(s) protocol.
By default, Connhex only implements pull updates, since they are better suited for heavy updates. Should your situation be better suited for push updates, you can contact us as usual!
Flow
The firmware update process begins with building and uploading the firmware package. Each firmware can have multiple versions, with each version identified by a unique version
. However, only one version can be active at a time. The active version is the one that will be downloaded and applied by the device during an update if no other constraints are in place.
Devices can periodically check for updates by providing the current version they are running or the timestamp of the last update check. If a new firmware version is available, the server will return the new binary for download.
Downloading Updates
There are two main methods for checking and downloading firmware updates:
- Check Only: Determines if a new firmware version is available without downloading it.
- Check and Download: Determines if a new firmware version is available and downloads it if so.
The API supports both behaviors depending on the HTTP method used:
- Use the
HEAD
method to check for updates without downloading. - Use the
GET
method to check for updates and download the firmware.
The GET
method also supports partial downloads using the Range
header, allowing for efficient handling of large files, resuming interrupted downloads, and more.
Authentication
The device must authenticate using init_id
and init_key
credentials. Only initialized devices are permitted to access OTA updates, so other credentials, such as migration_key
, cannot be used for this purpose.
Checking for Updates
To check if a new firmware version is available, the device can send a HEAD
request to the server.
It is recommended to include the If-Modified-Since
(or the complementary If-Unmodified-Since
) header with the timestamp of the last firmware check. This allows the server to respond with a 304 Not Modified
status if the firmware has not been updated since the provided date, saving bandwidth and processing time.
Other conditional headers, such as If-None-Match
and If-Match
, can also be used to check for updates based on the ETag value, for example to check if a specific version is available.
Example Request filtering by last update check
HEAD /iot/edge/ota/<init_id> HTTP/1.1
Host: <tenant>.connhex.com
Authorization: Thing <init_key>
If-Modified-Since: <date>
<init_id>
: The unique identifier of the device.<tenant>
: The tenant's domain for the server.<init_key>
: The key used for authenticating the device.<date>
: The timestamp of the last firmware check in HTTP-date format (e.g., Wed, 21 Oct 2023 07:28:00 GMT).
Example with curl
curl -I -H "Authorization: Thing <init_key>" \
-H "If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT" \
https://<tenant>.connhex.com/iot/edge/ota/<init_id>
Expected Response
200 OK
: A new firmware version is available.304 Not Modified
: The firmware has not been updated since the provided date.404 Not Found
: No firmware binary is available.
If a new firmware is available, the response will include the following headers:
Last-Modified
: The timestamp of the latest available firmware version.Content-Length
: The size of the firmware binary in bytes.Content-Type
: The MIME type of the firmware binary.Content-Disposition
: The suggested filename for the firmware binary.Content-Digest
: The checksum of the firmware binary in the format<algo>
=<checksum>
.Version
: The version of the firmware binary.Min-Version
: The minimum version required to apply the firmware binary (if applicable).Max-Version
: The maximum version allowed to apply the firmware binary (if applicable).ETag
: Unique identifier for the firmware binary (same as the version) to be used with theIf-Range
header.
Example Request filtering by version
HEAD /iot/edge/ota/<init_id> HTTP/1.1
Host: <tenant>.connhex.com
Authorization: Thing <init_key>
If-None-Match: "<version>"
<version>
: The version of the current firmware running on the device.
The server will respond with a 304 Not Modified
status if the firmware version is the same as the one provided in the If-None-Match
header, or a 200 OK
status if a new version is available.
The expected response is the same as in the example above.
Downloading the Firmware Binary
To download the firmware binary, use the GET
method. The binary can be downloaded in chunks using the Range
header, which is especially useful for large files. If the Range
header is not specified, the full binary will be returned.
Example Request
GET /iot/edge/ota/<init_id> HTTP/1.1
Host: <tenant>.connhex.com
Authorization: Thing <init_key>
Range: bytes=<start>-<end>
<start>
: The starting byte position of the range.<end>
: The ending byte position of the range. This value is optional and, if omitted, the end of the resource is used as the end of the range.
Notes:
- The
Range
header uses a zero-based index, so the first byte is at position 0. - The
<end>
value is inclusive, meaning the byte at that position is included in the range. - When the
<end>
is omitted, the-
character must still be present (e.g.,bytes=512-
).
Example with curl
curl -H "Authorization: Thing <init_key>" \
-H "Range: bytes=0-1023" \
-o firmware_part_1.bin \
https://<tenant>.connhex.com/iot/edge/ota/<init_id>
This command downloads the first 1024 bytes of the firmware binary and saves it as firmware_part_1.bin.
Downloading the Entire Binary
If you prefer to download the entire binary at once:
curl -H "Authorization: Thing <init_key>" \
-o firmware.bin \
https://<tenant>.connhex.com/iot/edge/ota/<init_id>
This will download the complete firmware binary and save it as firmware.bin.
Expected Response
200 OK
: The full firmware binary is returned (if no Range header is provided).206 Partial Content
: The requested byte range of the firmware binary is returned.416 Range Not Satisfiable
: The requested byte range is invalid or out of bounds.404 Not Found
: The firmware binary is not available.
The response will include the same headers as the update check response.
In the case of partial content, the Content-Range
header will also be included, indicating the range of bytes being returned.
Using If-Range for resuming downloads
The If-Range
header is useful when resuming a partially downloaded firmware binary. It ensures that the server sends only the missing portion of the binary if it hasn't been modified since you last checked. If the firmware has been updated, the server will ignore the Range header and send the entire binary instead.
Note that the If-Range
header can only be used together with the Range
header.
Example Request
GET /iot/edge/ota/<init_id> HTTP/1.1
Host: <tenant>.connhex.com
Authorization: Thing <init_key>
Range: bytes=1024-2047
If-Range: "<etag>"
<etag>
: The ETag value received from the previousGET
orHEAD
request, indicating the active version of the firmware.
Example with curl
curl -H "Authorization: Thing <init_key>" \
-H "Range: bytes=1024-2047" \
-H 'If-Range: "<etag>"' \
-o firmware_part_2.bin \
https://<tenant>.connhex.com/iot/edge/ota/<init_id>
This command requests the next 1024 bytes of the firmware binary, but only if the binary hasn't changed since the last download, as indicated by the ETag.
Expected Response
206 Partial Content
: The requested byte range of the firmware binary is returned.200 OK
: The full firmware binary is returned because the binary was updated, rendering the range request invalid.416 Range Not Satisfiable
: The requested byte range is invalid or out of bounds.404 Not Found
: The firmware binary is not available.
Verifying the Download
After downloading the firmware, verify its integrity by comparing the checksum provided in the Content-Digest
header with the checksum you calculate for the downloaded file. For example, using sha256sum:
sha256sum firmware.bin
Ensure the checksum matches the one provided by the server to confirm the binary is intact and uncorrupted.
Here is an example script that downloads the firmware binary and verifies its checksum:
#!/bin/bash
URL="https://<tenant>.connhex.com/iot/edge/ota/<init_id>"
AUTH="Thing <init_key>"
OUTPUT_FILE="firmware.bin"
# Make the HTTP GET request to download the file and capture the Content-Digest header
CONTENT_DIGEST=$(curl -s -H "Authorization: $AUTH" -D - $URL -o $OUTPUT_FILE | grep -i "Content-Digest" | awk '{print $2}' | tr -d '\r')
# Extract the algorithm and checksum from the Content-Digest header
ALGO=$(echo $CONTENT_DIGEST | cut -d '=' -f 1)
EXPECTED_CHECKSUM=$(echo $CONTENT_DIGEST | cut -d '=' -f 2)
# Calculate the checksum of the downloaded file using the specified algorithm
if [[ "$ALGO" == "sha256" ]]; then
ACTUAL_CHECKSUM=$(sha256sum $OUTPUT_FILE | awk '{print $1}')
elif [[ "$ALGO" == "sha1" ]]; then
ACTUAL_CHECKSUM=$(sha1sum $OUTPUT_FILE | awk '{print $1}')
elif [[ "$ALGO" == "md5" ]]; then
ACTUAL_CHECKSUM=$(md5sum $OUTPUT_FILE | awk '{print $1}')
else
echo "Unsupported checksum algorithm: $ALGO"
exit 1
fi
# Compare the checksums
if [[ "$EXPECTED_CHECKSUM" == "$ACTUAL_CHECKSUM" ]]; then
echo "Checksum matches!"
else
echo "Checksum does not match!"
exit 1
fi
Applying the Update
Once the update is available, a re_init
message can be sent to any device - either manually or programmatically1. Upon receiving the re-initialization message2, Connhex Edge will:
- download the update, by authenticating with the usual
init_id
andinit_key
credentials - overwrite the update folder (typically
/opt/connhex/updates
) - perform the initialization process once again
For additional security, upon the receival of a download request, a token can be generated and exchanged before downloading the file.