Azure offers an over-the-air update (OTA) service called Azure Device Update (ADU).
This service can be used side-by-side with your Azure IoT Hub to update your device fleet.
You can see this video with all the steps to experience OTA with ADU through the samples available for Azure IoT Middleware for FreeRTOS.
This guide will show you how to use the ADU Agent client API in your device application to support OTA with ADU.
- Introduction
- Azure Device Update in a Nutshell
- Azure IoT Middleware for FreeRTOS ADU client API and ADU Agent Logic
- Support
- Contributing
- License
- Trademarks
Azure Device Update is implemented using a server-client architecture.
The components of the OTA update process using ADU are:
- the ADU Service
- the ADU Agent
- an update binary image
- its corresponding import manifest.
The ADU service works in conjunction with Azure IoT Hub, leveraging the Azure Device Twin feature to deliver OTA update requests and consume ADU Agent state updates. It offers an user-interface through Azure Portal for customers to trigger, manage and monitor device updates.
To initiate an OTA update a customer would have a new binary image ready for their device(s) (with the new version of their code to update the device to), and generate an ADU import manifest document (which contains the name of that binary file plus additional details pertinent to the update process).
After uploading this import manifest to the ADU service and triggering the update, the ADU service delivers the update request (with the import manifest
converted into what is called an update manifest
) to the target device(s) by publishing that request in the device(s) Twin Document.
The ADU client API ("ADU Agent") provides functions to properly parse OTA update requests and provide state updates to the ADU service, on top of the Azure Device Twin feature as well.
Once a device boots up, the first step to make itself eligible to be updated through ADU (a.k.a, be an ADU Agent) is to send a state update to the ADU service informing the device details (e.g., manufacturer, model, etc), the version of the current device image and the ADU agent state (idle, in-progress, or error).
Then the device application must wait for any Device Twin desired properties update, and check if the properties received are related to an ADU OTA update request (using one of the functions of the Azure IoT Middleware for FreeRTOS ADU client API). If it is an ADU OTA request, then the device application can parse, validate and use the request data for the OTA update. Once the update is completed, the device informs the ADU service about its ADU Agent state again and the new version of its image.
For more and in-depth details please refer to the Azure Device Update official documentation.
The Azure IoT Middleware for FreeRTOS ADU Client API is exposed by azure_iot_adu_client.h.
Each of the functions in that header contain a full description of their functionality, arguments and return values.
For a device application to be recognized as an ADU Agent (and thus be able to be updated through ADU), the following sequence of events and function calls must occur:
-
The device must connect to the Azure IoT Hub and subscribe for Device Twin updates.
Please refer to function
AzureIoTHubClient_SubscribeProperties
in this sample code for how to subscribe for Device Twin updates. -
Initialize the Azure Device Update client.
Similar to the Azure IoT Hub client structure, the Azure Device Update client (
AzureIoTADUClient_t
) must also be initialized before it can be used with any of the functions below. For initializing it, callAzureIoTADUClient_Init
. -
Send the current ADU Agent state to the ADU Service.
Call the function
AzureIoTADUClient_SendAgentState
, as shown inprvAzureDemoTask
within this sample code. That will inform the ADU Service which device this is (manufacturer, model), the version of its image and the state (in this case that this device is ready to receive updates). -
Then, each time a Device Twin Desired Properties message arrives, check if the properties contains a "deviceUpdate" component using
AzureIoTADUClient_IsADUComponent
.A device twin notification payload must be verified if the payload type is either
eAzureIoTHubPropertiesRequestedMessage
(resulting from a Device Twin GET request from the device client) oreAzureIoTHubPropertiesRequestedMessage
(a Device Twin desired properties notification sent by the Azure IoT Hub). Please see an example withAzureIoTADUClient_IsADUComponent
here. -
If
AzureIoTADUClient_IsADUComponent
returns true, the component in the Device Twin can be parsed into an usable data structure (AzureIoTADUUpdateRequest_t
) usingAzureIoTADUClient_ParseRequest
.Note that the information in the request can be to start a new update, as well as to cancel an existing one. This can be verified through the property in
AzureIoTADUUpdateRequest_t.xWorkflow.xAction
, which will have eithereAzureIoTADUActionApplyDownload
(start a new update) oreAzureIoTADUActionCancel
. If it is to start a new update, this data structure will contain theADU update manifest
document, a signature for validation, as well as link(s) for downloading the update image(s). -
Next the device application must validate the
ADU update manifest
.The validation is done using function
AzureIoTJWS_ManifestAuthenticate
and the Azure Device Update certificate root keys. An example of the usage ofAzureIoTJWS_ManifestAuthenticate
can be found in sample_azure_iot_pnp_simulated_data.c. -
Once validated, send a response to ADU Service accepting or rejecting the update request.
This is done using
AzureIoTADUClient_SendResponse
, with eithereAzureIoTADURequestDecisionAccept
oreAzureIoTADURequestDecisionReject
as response. Internally, this function publishes the response in the Device Twin reported properties, which are then read by the ADU Service.A device could reject an update request if it is busy, for example. The ADU Agent will receive that same update request again later whenever it gets its Device Twin desired properties again (e.g., if it reboots).
At this point the device application should exit the Device Twin notification function and process the update request within a separate task. That will allow the device to still receive other Device Twin notifications, with perhaps a cancellation if that is ever triggered by the user.
-
Send an ADU Agent state update to the ADU Service with an in-progress status.
If the update request is for a new update and the device (ADU Agent) decides to accept it, call
AzureIoTADUClient_SendAgentState
with aeAzureIoTADUAgentStateDeploymentInProgress
state to inform the ADU Service that the update is in progress. -
Download update image(s) and write to Flash memory.
The device application must iterate through the files in the update request, download them and write them to flash memory as applicable.
The links to the binaries to be downloaded are stored in
AzureIoTADUUpdateRequest_t.pxFileUrls[]
. Each downloaded file shall be validated against its hash present inAzureIoTADUUpdateRequest_t.xUpdateManifest.pxFiles[].pxHashes[]
.The Azure IoT Middleware for FreeRTOS provides an interface implemented on top of FreeRTOS' coreHTTP library to help download the binary files referenced in the update request. Header azure_iot_http.h exposes the following functions:
AzureIoTHTTP_RequestSizeInit
AzureIoTHTTP_RequestSize
AzureIoTHTTP_Init
AzureIoTHTTP_Request
AzureIoTHTTP_Deinit
See
prvDownloadUpdateImageIntoFlash
in sample_azure_iot_adu.c for an example how to use these functions to download and write images to flash memory.If an update fails (e.g., downloading the image files, or writing to flash),
AzureIoTADUClient_SendAgentState
must be called twice; once with stateeAzureIoTADUAgentStateFailed
, followed by another call with stateeAzureIoTADUAgentStateIdle
(with the same image version as before the update request). -
Reboot device and load new image.
At this point the device application must set the device to load the new image version upon reboot. This usually involves setting the bank or partition with the new image version (just downloaded) as active/enabled.
Once that is done, the device application must restart and load the new image version.
See
prvEnableImageAndResetDevice
in sample_azure_iot_adu.c. -
Send the ADU Agent state to the ADU Service.
Once the device update is successfully completed the device application must inform the ADU Agent state to the ADU Service.
This is also done with
AzureIoTADUClient_SendAgentState
. It will inform the ADU Service which device this is (manufacturer, model), the version of its new image (if successful) and that this device is ready to receive updates (stateeAzureIoTADUAgentStateIdle
).
flowchart TD;
Begin --> connect[Connect to Azure IoT Hub];
connect --> subscribe[Subscribe for</br>Device Twin</br>Notifications];
subscribe --> AzureIoTADUClient_Init;
AzureIoTADUClient_Init --> aduAgentIdle[AzureIoTADUClient_SendAgentState</br>with state </br>eAzureIoTADUAgentStateIdle];
aduAgentIdle --> twinReceived{Device Twin</br>desired properties</br>received?};
twinReceived -- No --> mainLoop[Run Device Application];
twinReceived -- Yes --> AzureIoTADUClient_IsADUComponent[Run AzureIoTADUClient_IsADUComponent</br>on Device Twin desired properties];
mainLoop --> twinReceived;
AzureIoTADUClient_IsADUComponent --> isAduComponent{Is ADU component?};
isAduComponent -- No --> mainLoop;
isAduComponent -- Yes --> AzureIoTADUClient_ParseRequest;
AzureIoTADUClient_ParseRequest --> authenticateRequest[AzureIoTJWS_ManifestAuthenticate];
authenticateRequest --> isAuthenticated{Is request authenticated successfully?};
isAuthenticated -- No --> rejected;
isAuthenticated -- Yes --> updateAccepted{Is device update accepted?};
updateAccepted -- No --> rejected[AzureIoTADUClient_SendResponse</br>with</br> eAzureIoTADURequestDecisionReject];
rejected --> mainLoop;
updateAccepted -- Yes --> accepted[AzureIoTADUClient_SendResponse</br>with</br> eAzureIoTADURequestDecisionAccept];
accepted --> aduAgentInProgress[AzureIoTADUClient_SendAgentState</br>with state</br>eAzureIoTADUAgentStateDeploymentInProgress];
aduAgentInProgress --> downloadImages["Download image file(s)</br>and write to persistent</br>storage (e.g., flash)"];
downloadImages --> updatedSuccesfully{Is device update successful?};
updatedSuccesfully -- No --> aduAgentFailed[AzureIoTADUClient_SendAgentState</br>with state</br>eAzureIoTADUAgentStateFailed];
aduAgentFailed --> aduAgentIdleAfterFailed[AzureIoTADUClient_SendAgentState</br>with state </br>eAzureIoTADUAgentStateIdle];
updatedSuccesfully -- Yes --> reboot[Reboot device and</br>boot up from new</br>image version];
aduAgentIdleAfterFailed --> mainLoop;
reboot --> connect;
If you need support, please see our SUPPORT.md file.
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.
Azure IoT Middleware for FreeRTOS is licensed under the MIT license.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.