Introduction
One of the key features of Azure Sphere and one of the 7-properties of a highly secure device is Renewable Security. Think about a deployed IoT device, or thousands of devices, that don't have the ability to be updated remotely. These devices may be considered secure when they ship, but as time goes by, clever hackers may find vulnerabilities or the engineering community may find issues with common operating systems that need to be patched. Without the ability to remotely update these devices they can become unsecure. Additionally, OEM applications may need to be updated to add new features, or to fix a software bug that was discovered.
The Azure Sphere ecosystem provides Over-the-Air (OTA) updates for the Operating System but also provides methods and global infrastructure for OEMs/developers to manage/deploy application images OTA. This is a free feature that is included for all Azure Sphere devices.
OTA Update Specifics
Microsoft has detailed documentation on setting up OTA updates here, and deferring OTA updates here. I recommended that you review that documentation. One Azure Sphere OTA behavior that is sometimes seen as a negative, is that OTA updates can trigger at any time. And when they do, the device will download the update and proceed to apply the update to the device. This includes restarting the device so that the updates are used right away. Microsoft recognized that this behavior is less than ideal for many devices, so they include the ability for high level applications to defer updates.
When do OTA updates trigger?
Over the Air updates are managed by the Azure Sphere Security Service (AS3) in the cloud. Azure Sphere devices connect to AS3 for Device Authentication and Attestation (DAA) activities. DAA is the process where the AS3 validates that the device is a genuine Azure Sphere device and that the device is running the correct OS and Application versions. If the DAA step identifies that the device is running old or unauthorized software, then the OTA process kicks off. The DAA process starts when the device first powers on, and then approximately every 24-hours. So any given Azure Sphere device could receive an update at any time of the day, it depends on the time of day when the device last powered up. There is currently not a mechanism to schedule when updates are pushed to devices, or a way for the Azure Sphere application to ask AS3 if there is an update pending.
OTA Events
At a high level the Azure Sphere High Level application registers for OTA events and provides a handler that will be called when OTA events trigger. The events are shown below, note that there is a 10 second window where the application has the opportunity to defer the update.
Note that there is a limit to how long the application is allowed to defer the updates. For OS updates the limit is 24 hours, and for application updates the limit is 167 hours (~7 days) . These time periods start when the application gets the first notification that an update is pending. If the application asks for a deferment period greater than the remaining allowed period, the requested period is adjusted to reflect the max time remaining.
OTA Deferment Example Applications
Microsoft has published a simple straight forward example demonstrating how to use this feature. You can review the example here.
Avnet Example
I've recently developed and published an Azure Sphere implementation that allows applications to manage OTA updates. The Avnet implementation implements the following features . . .
- Poll for the current OTA status
- This functionality could be useful if your application frequently powers down to conserve power. Before powering down, make sure an update is not in progress or pending. If so, don't power down, allow the update!
bool OtaUpdateIsInProgress(void);
bool OtaUpdateIsPending(void);
- Defer and resume OTA updates if they come in
- This functionality could be useful if your application enters a critical section (brewing coffee for example) and should not be interrupted
void delayOtaUpdates(uint16_t pausePeriod);
void allowOtaUpdates(void);
- Device twin handler that allows the user to configure a specific target time of day for any future OTA updates from the cloud
- This functionality will defer any future updates until a specific target time of day
- This could be useful if your device is installed in a business that is closed overnight
- The target time of day data is written to mutable storage so that if the device resets or power cycles, the target time is read and known on future power-on/reset events
- Since the device performs the DAA step on power-up, it's critical that the target time of day is known on power-up
Avnet Source
You can review/reuse the Avnet implantation by pulling our Azure Sphere GitHub repo
- Repo link
- Note you need to pull the entire repo to use the examples since the Hardware definitions are in the root directory structure
Example projects
There are two examples in the repo that use this implementation. Both examples have been written to help Azure Sphere Developers quickly implement full featured Azure Sphere applications (expect more blogs on these examples soon). Please see the README.md files for each example.
How to use the example
If you leverage the Avnet examples, you just need to enable the feature by enabling the compile flag in common/build_options.h
Device Twin Details
To set a target time of day for OTA installs from the cloud, you just need to update the device twin desired properties
{"otaTargetUtcTime": "04:21:00"}
This entry will tell the application to only apply OTA updates at 4:21 AM UTC, 12:21 AM here in North Carolina (UTC -4).
Use the example in your Azure Sphere application
To port the example into your project . . .
- Include the avnet/deferred_update.c and avnet/deferred_update.h files in your project
- Add the deferred update specific ExitCodes into your ExitCode enumeration definition
- Call deferredOtaUpdate_Init() from your startup routine
- Call deferredOtaUpdate_cleanup() from your exit/cleanup routine
- Port the avnet/deferred_update.c::setOtaTargetUtcTime() device twin handler into your device twin implementation
- Search the example project for the compile flag DEFER_OTA_UPDATES to see all the required code
Execution Capture
Testing my implementation was tricky. I could not test the example from Visual Studio Code, since the only way I could get an OTA update to kick off was to update my OTA device group, then reset my device. I ended up using an Avnet Guardian 100 device that has an external USB port connected to the MT3620 ISU1 UART. I added code to write OTA debug to ISU1 and monitored a teraTerm terminal window. I also added Azure IoTHub telemetry messages to capture the events. I thought this would be a nice feature to use in the field as OTA events could be captured as telemetry and reviewed to see when a device received an OTA event and how it responded to the event.
Marked up debug with my comments in Bold
// Application running . . .
// Send device twin to defer updates until 05:10:00 PM UTC
TX Reported State: {"otaTargetUtcTime":"17:10:00"}
// Upload new image to my Device Group
// Power cycle device so it gets the update
Avnet Guardian 100 Default Application starting.
// Device receives OTA event "Pending"
// Attempts to send telemetry with event details, but not connected to IoTHub so telemetry gets queued (see ENABLE_TELEMETRY_RESEND_LOGIC feature
// Delay OTA update for 5 minutes
TX Telemetry: {"otaUpdateType":"Application","otaUpdateStatus":"Pending","otaMaxDeferalTime":10020}
deferredOtaCallback(): Pending
INFO: Deferring update for 5 minutes.
TX Telemetry: {"otaUpdateDelayPeriod":5}
TX Telemetry: {"otaUpdateType":"Application","otaUpdateStatus":"Deferred","otaMaxDeferalTime":10020}
// Device receives OTA event "Deferred"
deferredOtaCallback(): Deferred
INFO: Update deferred.
// Application connects to IoTHub
// Sends queued up telemetry messages
Azure IoT connection status: IOTHUB_CLIENT_CONNECTION_OK
TX Reported State: {"versionString":"AvnetG100Template-V2","manufacturer":"Avnet","model":"Azure Sphere Guardian 100"}
TX Telemetry: {"otaUpdateType":"Application","otaUpdateStatus":"Pending","otaMaxDeferalTime":10020}
TX Telemetry: {"otaUpdateDelayPeriod":5}
TX Telemetry: {"otaUpdateType":"Application","otaUpdateStatus":"Deferred","otaMaxDeferalTime":10020}
// Receives device twins desired properties messages
TX Reported State: {"sensorPollPeriod":15}
TX Reported State: {"telemetryPeriod":30}
TX Reported State: {"enableUartDebug":true}
TX Reported State: {"ssid":"IoTDemo","freq":2437,"bssid":"e4:95:6e:4c:7b:b6"}
TX Reported State: {"otaTargetUtcTime":"17:10:00"}
// Device receives OTA event "Pending" when time defer time expires
deferredOtaCallback(): Pending
// Logic allows update
// Device receives OTA event "Final" because OTA update has completed
INFO: Allowing update.
TX Telemetry: {"otaUpdateType":"Application","otaUpdateStatus":"Final","otaMaxDeferalTime":0}
deferredOtaCallback(): Final
INFO: Final update. App will update in 10 seconds.
// Device restarts
Avnet Guardian 100 Default Application starting.
// Device receives OTA event "Completed"
TX Telemetry: {"otaUpdateType":"Application","otaUpdateStatus":"Completed","otaMaxDeferalTime":0}
deferredOtaCallback(): Completed
INFO: OTA Update completed!
Avnet Over the Air Lab Documents
Avnet has created OTA update lab documents that contain all the details on how to create and manage Azure Sphere OTA deployments. You can download these documents by clicking on the graphics below.
Avnet Over the Air Lab Video Walk Through
We have created a video walking through the OTA Lab. If you want to see the lab in action, just click on the graphic below, the video is 32 minutes long.
Conclusion
I hope you learned something about Azure Sphere OTA updates and how to defer them from your application. I hope you'll be able to reuse the code I developed to configure OTA update target time of day from the cloud. I had fun developing it. If you have any comments, questions, or find issues with my code. Please don't hesitate to leave a comment.
Future improvements . . .
- Add the ability to set a local target OTA update time of day (not UTC)