IoT solutions are required to provide a mechanism for devices to update their own software. Supporting software updates without human intervention is both critical for scaling solutions to millions of devices and for delivering a great customer experience. However, achieving a full update of large sets of devices in a secure, scalable, and reliable fashion requires a solution that can scale to meet device load, a resilient command mechanism, and a way of tracking the state of the entire fleet of devices.
IoT solutions that leverage the Command and Device State Replica patterns alongside a globally available and scalable storage solution are able to meet all the challenges inherent in updating the software of devices in a large fleet.
The Software Update pattern shown in the following diagram can deliver this functionality.
state/deviceID/update/delta
upon which device-related state change messages will arrive from the device state replica.state/deviceID/update
. The desired state message contains a software update URL different form the device’s current software version URL.state/deviceID/update/delta
that is sent to the device.state/deviceID/update
and a device state replica tracking this device records the new state in a persistent data store.state/deviceID/update/accepted
topic. The software update is now considered complete.When implementing this pattern, consider the following questions:
The solution can ensure that only the device targeted for a software update can obtain the update by using a pre-signed URL or a temporary credential. Each approach has different considerations.
Pre-signed URL - the benefit of a pre-signed URL is that it constrains the ability for a device to download a software update within a period of time and by devices with specific public IP addresses. The negative of this approach arises when the device downloading the the update does not have a publicly resolvable IP address. Without a publicly resolvable IP address the solution can only place a time boundary on the interaction with the software update. The practitioner of a solution may or may not find this acceptable.
Temporary Credential - a device interacts with the solution to obtain a temporary credential associated with only the privilege of accessing the storage solution to download the update. The benefit of using a temporary credential is that only the device with that credential can access the update, even when the device does not have a publicly resolvable IP address. The slight negative of this approach is that it requires the device and solution to be more complex because the device must go through a separate process to obtain temporary credentials.
An example of the logic involved for a device in an IoT solution to receive and execute an “update” command received through a Device State Replica. Specifically, the device will obtain new software, perform an update using that software, and acknowledge completion.
A device subscribes a message listener function to process command messages coming from the state/deviceID/update/delta
topic
def message_listener(message):
# ..do something with 'message'..
def main():
# subscribe the message listener function to the topic
sub = topic_subscribe('state/' + device_id + '/update/delta', message_listener)
# now wait until the program should end
wait_until_exit()
After some time passes the device receives a delta message that acts as the ‘software update’ command message.
def message_listener(message):
# parse the message from raw format into something the program can use
msg = parse_message(message)
# determine if the message is an update command type
if msg is UPDATE_COMMAND:
# get the globally unique job ID from the command message
job_id = msg.get_job_id()
# read the software update URL from the command message
url = msg.read_value('softwareURL')
# download the software from the given URL
software = download_software(url)
# ..and apply the software update triggered by the specific job ID
apply_software(software, job_id)
A device will apply the downloaded software and acknowledge the command completion with a message to state/deviceID/update
topic
def apply_software(software, job_id):
# do the local, device-specific work to apply the software
# and produce a result value of SUCCESS or FAILURE
if result is SUCCESS:
# make a success message
message = 'jobID:' + job_id + " SUCCESS"
else:
#make a failure message
message = 'jobID:' + job_id + " FAILURE"
# the topic used to publish the acknowledge message
topic = 'state/deviceID/update'
# ...and finally, publish the acknowledge message
message_publish(topic, message, quality_of_service)