SoftwareUpdatable feature detailed specification and integration guide
This page describes the SoftwareUpdatable feature, which needs to be implemented in your device firmware in order to make your device able to get software updates via Bosch IoT Rollouts.
Table of contents:
Diagram
Feature and entities contained in the feature
softwareModuleType |
String |
required |
The type of software(-module) this feature is responsible for |
Bosch IoT Rollouts will import all found softwareModuleTypes and will use this type in order to find out the feature on which the install operation will be invoked. A software-module type is usually the type of software which is managed by this feature. Examples could be "OS", "bundle", "docker", "feature", "app" or just "software". If one SoftwareUpdatable feature implementation is responsible for multiple types, it can decide to represent itself as multiple SoftwareUpdatable features on the thing, or can just offer a generic type like "software".
|
installedDependencies |
dictionary [String,DependencyDescription] |
optional |
A list of all installed "pieces of software" which are managed by this feature |
A list of "group", "name" and "version" from all artifacts which are managed by this feature (could be potentially updated or removed). The key in the dictionary should be the combined group.name:version of the dependency (please see examples below). Examples:
The installed and context dependencies are currently not actively used by Bosch IoT Rollouts but will be used in a planned extension which requires a better understanding of the real state of a device, i.e. when the device gets "offline" modifications (hardware or firmware). |
contextDependencies |
dictionary [String,DependencyDescription] |
optional |
A list of all other dependencies which do influence the artifacts managed by this feature |
This could be e.g. a certain hardware version or processor architectures. The content depends on the project requirements. For example, if there is only one version of hardware out in the field or the updates contain all "drivers" for all kinds of hardware, there is no need to know if the assigned updates are matching the device or not. A better understanding of the real state of a device will be required by a future extension of Bosch IoT Rollouts with update-build support, validity checks of assignments and auto-update proposals. From a device point of view, there is no need to know about dependency relationships (e.g. which software requires which hardware). This is tracked and modeled on the server-side. |
lastOperation |
Entity<OperationStatus> |
(required) |
The last operation response received from the device |
Status updates on this property are recorded by Bosch IoT Rollouts in order to follow the progress of the installation. In case of multi-assignment, this field might be updated in a quick sequence, still Bosch IoT Rollouts will be able to map the updates to the matching assignment with the help of the correlationId in the OperationStatus. The lastOperation may not be present if no operation has been executed so far. |
lastFailedOperation |
Entity<OperationStatus> |
(required) |
The last operation response which has had an error-status |
The lastFailedOperation may not be present if there has been no failed operation so far. In case that an operation finishes with FINISHED_ERROR, FINISHED_WARNING or FINISHED_REJECTED, the device should not only update the lastOperation but also in addition the lastFailedOperation. Background: In case that there are multiple operations running, the lastOperation might be overwriting quickly and not be preserved to be used in a thing-search later. |
status |
Enum<Status> |
required |
A status describing the current state of the installation on the device |
Must be not empty - a status can be sent multiple times e.g. for transmitting different steps in the message/statusCode within the status "IN_PROGRESS" |
message |
String |
optional |
Any kind of message giving additional information |
Any kind of additional information provided by the device in order to report installation steps or errors. |
progress |
number |
optional |
A number defining the progress in percentage (0...100) |
An optional progress indicator which can be used by 3rd party UIs in order to visualize a progress. |
correlationId |
String |
required |
The correlation ID passed from Bosch IoT Rollouts with the install/download instruction |
This ID is essential for matching the responses of the device to the instructions generated by Bosch IoT Rollouts. |
statusCode |
String |
optional |
A custom code which can be used for grouping and retrying failed assignments |
A custom error code which can be used by the user of Bosch IoT Rollouts in order to filter for devices which might belong to the same retry strategy. |
softwareModule |
Entity<SoftwareModuleId> |
(required) |
The name and the version of the SoftwareModule which is installed |
The name and version of the module currently processed. As the name and version of SW-modules are unique across all updates they identify always exactly the same module. This property is only required in the case of an install/download or cancel operation. |
software |
optional |
In the case of a remove operation status, the currently processed software |
Can be used to indicate the currently removed software. |
group |
String |
required |
An identifier which groups the dependency into a certain category. |
Groups (or vendor) are usually used in order to ensure that the dependency names (with version) get globally unique. A good practice is to use "reverse" domain names like "io.bosch.rollouts" if possible. In order to choose good and unique groups/name combinations for context dependencies, please refer to the list of commonly used patterns (see below). A recommended limitation is: numbers uppercase & lowercase letters (a-z & A-Z), underscore (_), dot (.) and dash (-). |
name |
String |
required |
The name of the dependency |
The name should uniquely identify the software or hardware within the group. A recommended limitation is: numbers uppercase & lowercase letters (a-z & A-Z), underscore (_), dot (.) and dash (-). |
version |
String |
required |
A version identifier |
A version specification. Basically all version patterns are allowed. If this information is used within a packaging process where Gradle or Maven is used version-specifications need to be compliant with the requirements there. A recommended limitation is: numbers uppercase & lowercase letters (a-z & A-Z), underscore (_), dot (.) and dash (-). |
type |
String |
optional |
A "category" classifier for the dependency |
A type classifier. If not provided it is assumed that the dependency is some kind of "installable" software. Other suggested types are listed in the table "Recommended dependency descriptions patterns" (s. below). It is not recommended to invent new types. |
Operations and entities used as arguments
SoftwareUpdatable (Operations) |
||||
install() |
Entity<SoftwareUpdateAction> |
required |
trigger an installation |
Instructs the device to download and install the artifacts defined in the SoftwareUpdateAction. Important: the device must acknowledge the install command to Bosch IoT Hub/Bosch IoT Things immediately after receiving it and not wait until the complete installation is done. Otherwise the install will be re-delivered every time the device comes back online. Depending on the implementation on the device this might result in endless-loops. |
download() |
Entity<SoftwareUpdateAction> |
required |
trigger a download for a potential installation |
Instructs the device to only download but not install the artifacts defined in the SoftwareUpdateAction. A subsequent installation will be triggered by a call of the install operation with the same parameters. If the artifacts have been downloaded before, this step can then be skipped. |
cancel() |
Entity<SoftwareUpdateAction> |
required |
The action to be canceled |
A cancel operation can be ignored by devices if not supported or sent too late. The expected OperationsStatus should have the status "FINISHED_CANCELED" if successfully canceled. If the operations was received but could not be canceled (either too late or by user interaction) this can be communicated with the "CANCEL_REJECTED") state. |
remove() |
Entity<SoftwareUpdateAction> |
optional |
Remove/uninstall the specified feature |
e.g. uninstall or deactivate a "snap" → not used by rollouts yet |
cancelRemove() |
Entity<SoftwareUpdateAction> |
optional |
Try to cancel the removal |
A cancel operation can be ignored by devices if not supported or sent too late. |
correlationId |
Entity<SoftwareModuleId> |
required |
The name and the version of the SoftwareModule which should be installed |
The name and the version of the Software Module to be installed. |
softwareModules |
Array[Entity<SoftwareModuleAction>] |
optional |
An array of software artifact specifications which should be installed. |
The list of software artifact specifications can be empty when the most important information for the device is in the metadata. This is sometimes used in order to transmit just a URL or a configuration to the device. |
weight |
int |
optional |
In the case of multi-assignment, weight defines the precedence of the updates. |
In case that "multiple parallel assignments" is active, multiple different update actions may arrive at the device. The device can decide to install them in the sequence as they arrive - or take the weight as аn indicator of which one should be installed first. |
forced |
boolean |
optional |
A flag which gives the device an indicator about the urgency. |
Forced can be interpreted in the project context as e.g. "do not" ask the user and "apply immediately". Soft (forced =false) could mean "wait until night-times" or ask user to apply. The default is usually soft. |
metadata |
Dictionary[String,String] |
optional |
Any kind of additional information which should be transmitted to the device |
This information can be entered in the Bosch IoT Rollouts UI or added via API to a distribution set |
softwareModule |
Entity<SoftwareModuleId> |
required |
The name and the version of the SoftwareModule which should be installed |
The name and the version of the Software Module to be installed. |
artifacts |
Array[Entity<SoftwareArtifactAction>] |
optional |
An array of software artifact specifications which should be installed. |
The list of software artifact specifications can be empty when the most important information for the device is in the metadata. This is sometimes used in order to transmit just a URL or a configuration to the device. |
metadata |
Dictionary[String,String] |
optional |
Any kind of additional information which should be transmitted to the device |
This information can be entered at the Bosch IoT Rollouts UI or added via API to a software module. |
fileName |
String |
required |
The real file name of the artifact behind the provided URLs |
The file name in the URL must not be the same as this one, as depending on the used CDN the name in the URL can be auto-generated. |
size |
int (Bytes) |
required |
The size of the file in bytes |
|
checksums |
Dictionary[Hash,String] |
required |
Checksums to verify the proper download |
Currently, Bosch IoT Rollouts supports "SHA1", "MD5" and "SHA256" where all hash-values can be found in this array. |
download |
Dictionary[Protocol,Links] |
optional |
Array of download options for the artifact |
Depending on the cloud and the activated options there can be multiple protocols available. Currently - on AWS - there is only HTTPS provided. In future there might be additional options provided. A protocol adapter/device should ignore protocols which it does not support. |
url |
String |
required |
URL for downloading the artifact |
The complete URL for downloading the artifact, described in the SoftwareUpdateAction. The URL contains also the protocol a) for the backwards compatibility to DDI and b) for avoiding unnecessary string concatenation operations on the device. Note that the URLs are usually only valid for a certain time frame (e.g. 30 days); if the device doesn't finish the update it must report a FINISHED_ERROR - we recommend to add a special errorCode to this operation status so that it is easy to filter and re-trigger the installation in such cases. |
md5url |
String |
optional |
URL for downloading an md5 file containing the md5 checksum for the artifact |
Additional URL for downloading an md5 sum file containing the md5 checksum of the artifact. Example content
d0b989e039fcb8ffa5b6399da1ee3d39 test.txt Most of the devices are using the checksums attribute in the SoftwareUpdateAction but this download option is also presented in order to be able to provide a Direct Device Integration (DDI) compatible API. |
removeList |
Array[Entity<DependencyDescription>] |
optional |
A list of installed features which should be removed from the device |
The list can only contain descriptions of software which are managed and therefore removable by the SoftwareUpdatable feature implementation. Not valid entries could be ignored or the complete action can be marked as failed. The software to be removed is addressed by the (unique) key of group, name & version within the DependencyDescription. |
forced |
boolean |
optional |
A flag which gives the device an indicator about the urgency. |
Forced can be interpreted in the project context as e.g. "do not" ask the user and "apply immediately". Soft (forced =false) could mean "wait until night-times" or ask user to apply. |
weight |
int |
optional |
In case of multiple, parallel remove actions an indicator of which one has more priority |
In case that multiple remove actions are received, the weight gives an indicator of which remove might have higher precedence than the other. |
metadata |
Dictionary[String,String] |
optional |
Any kind of additional information which should be transmitted to the device |
This information can be entered in the Bosch IoT Rollouts UI or added via API to a distribution set. |
Concept details
The SoftwareUpdatable feature
Bosch IoT Rollouts will scan devices for SoftwareUpdatable features and will use the softwareModuleType property in order to identify the feature on which it will call the install() operation for a certain software module.
Currently, Bosch IoT Rollouts does not check whether all devices have a matching feature when an assignment is made. If the device does not have a matching SoftwareUpdatable feature, an error occurs.
Uniqueness of features supporting software module types
As the feature responsible for a certain software module type is only identified by this property, it is not possible to have a second feature on the device/thing responsible for the same type.
Multi-version support
Bosch IoT Rollouts automatically detects the version of the implemented SoftwareUpdatable feature - there is no need to support multiple (protocol) versions for one software module type at the same time.
Still it would be possible that for example the OS updates use version 1.0 and the bundle updates already use version 2.0.
It is not possible to have a feature in version 1.0 for "bundles" and a second one in version 2.0 also responsible for "bundles" (uniqueness of responsibility violated).
Order of software modules/install operations
As of now, there is no order foreseen. All install operations will be executed at the moment the device is recognized as online. In case of any dependencies (e.g. OS has to be installed first), we recommend:
Without using multi-assignment: Two campaigns
→ Create a separate campaign to install the first dependency
→ Create a second campaign and query for the desired version in the installedDependency property to select only the devices where the artifact is allowed to be installedWithout using multi-assignment: One campaign
→ Put more intelligence on the device, add an install order or a pre-condition script to the artifacts in the software module. Such a dependency trace could also be automatically generated by the (future) complex-dependency management component of Bosch IoT RolloutsUsing multi-assignment: Two Campaigns
→ Create the first campaign, define a weight (e.g. 90)
→ Design a second campaign, with the artifact to be installed after the first one and define a low weight (e.g. 20)
When the device comes only it gets two install commands and can sort them by weight in order to know the sequence (Note that if there are multiple implementations of the SoftwareUpdatable feature present on the the device - they have to synchronize with each other about the order of the update-execution).
A potential future extension of Bosch IoT Rollouts might provide the possibility of ordering software modules and controlling the install operation sequence from the server-side (depends on customer demands).
Multi-architecture software modules
There is the demand to provide e.g. drivers in different versions depending e.g. on the hardware revision of the target device.
In order to realize such scenarios, there are the following options:
Create a campaign per hardware revision
Device version could be either identified by:Selecting a property/attribute in the device-thing representing the HW version (if the user knows a unique identifier here)
Selecting a value out of the contextDependencies - a property which is exactly meant to enable the device to announce such information
Having sorted the devices in a group or having them tagged according to the version of the driver which needs to get assigned.
Using one campaign - put the logic on the device
Put both drivers in the same software module and let the device decide which of them is the right one to be installed.
Download only and install
The device can be instructed to download the artifacts contained in the software modules without continuing the installation process afterwards (download operation). Download only can be used to prepare the device for a quicker install later.
The final status to be communicated after downloading is DOWNLOADED and then FINISHED_SUCCESS.
A subsequent installation will be triggered by calling an install operation containing the same SoftwareModuleActions. As SoftwareModules might be modified in between, the device must check if the contained artifacts have all been downloaded before or if some might have been changed, added or removed (ideally this should only rarely be the case).
Also it is up to the device to decide how long downloaded artifacts should be cached (probably depending on the available disc space). So it can be the case, that the artifacts are already cleaned-up when the install operation is called and that they have to be downloaded again.
Weight and forced
Weight and forced are properties of the SoftwareUpdateAction and SoftwareRemoveAction.
We recommend the following behavior:
In every case we recommend to not execute and update instruction immediately but to add a short delay, in order to wait if further instructions arrive (e.g. a cancel or a second update instruction).
Forced
Is a modification about the point-in-time of the execution. Forced = true means as soon as possible.
When forced = true:
Install the update immediately (after short delay) .
Do not wait or ask for "user feedback"
Do not wait until a probably configured maintenance window.
Do re-install if software with same version is already installed
When forced not present or forced = false (~= soft)
Consider to delay instructions to a random/configurable maintenance window e.g. once a day
Consider software as successfully installed when the version on the device is the same as requested to be installed
Of course legal aspects and the possibility of running an update depending on the device state have to be taken into account.
Weight
Gives an indication of the sequence of updates
In case when a weight is provided:
The device should take into account, that multiple install requests could arrive in a short time frame.
At the time of execution sort the instructions by their weight - higher weighted updates should be executed first.
In case that there are forced and not-forced updates sort the forced updates before the not-forced updates
Command-flow descriptions
Provision and initialization
A Device is created in Bosch IoT Manager/Things/Hub via the Device Provisioning API or the Bosch IoT Suite Console
The Device connects and reports its current state by creating features in Bosch IoT Things:
Option 1: The implementation(s) of the SoftwareUpdatable feature(s), on the device, create their corresponding SoftwareUpdatable feature in the digital twin (Thing-service) in order to reflect which type of software (→ softwareModuleType) can be installed on the device.
Option 2: There is a device-specific protocol adapter behind Bosch IoT Hub which knows exactly the capabilities of the devices in the field - all features can be created within the provision process.
Bosch IoT Rollouts identifies the updatable devices (SoftwareUpdatable features available) and identifies the accepted software types by looking at the softwareModuleType property.
Compose a campaign in Bosch IoT Rollouts
A user of Bosch IoT Rollouts creates one or more Software Modules in Bosch IoT Rollouts
In each Software Module the user uploads one or more Artifacts. Artifacts are arbitrary files e.g. could be a zip-file, binary images, lua-scripts, XML, ....
The user identifies the devices which should receive the update by specifying a Target Query (which is executed against the Device Inventory/ Bosch IoT Things).
The user creates a Rollout (=campaign) and references the previously composed Software Modules via one or more Distribution Sets as well as the desired Targets via the stored Target Query
The campaign can now been started.
Running the campaign
A campaign/rollout will generate one or more respective rules in the Mass Management Engine which is part of Bosch IoT Manager.
For each rollout group and detected software type a rule will be created which executes the install operation with the arguments described in the SoftwareUpdateAction as soon as the device becomes online (see Reflect device connectivity status in thing i.e. https://github.com/eclipse/vorto/tree/development/models/org.eclipse.ditto-ConnectionStatus-1.0.0.fbmodel support).
In order to communicate back the status of the update to Bosch IoT Rollouts, the Software Update Agent has to update its lastOperation status property (or in case of a failure, also the the lastFailedOperation status)
Bosch IoT Rollouts will receive all status changes and keep the history of them
Status transitions
In general, it is up to the device/driver implementation how many intermediate states are reported. Most important is, that one of the "finished" states is reported finally.
Keep also in mind, that there is a limitation about status reports per operation call: It is not allowed to report more than 1000 status updates!
It is common to report one and the same state multiple time (sее self-references on grey boxes) in order to report different messages ("progress or device logs") to the history in Bosch IoT Rollouts. Such "log messages" could be useful for identifying issues on the device while updating.
Download and install software modules & cancel installations
Removing software and cancel remove
Track installed software and context dependencies (optional feature)
For identifying applicable updates or analyzing inconsistencies, it is possible to provide current status of the installed software and other dependencies.
Installed dependencies (software)
Installed software means the downloaded and installed artifacts managed by the SoftwareUpdatable features containing the relevant properties. This includes the potential ability to update and/or remove this software.
Context dependencies
Context dependencies are any kind of dependencies which the SoftwareUpdatable feature may need in order to be able to successfully install or update downloaded artifacts. For example, for an OSGi bundle manager this is the version of the OSGi runtime or the currently installed JDK, but may also include hardware information like e.g. the CPU-architecture (ARM32, x86...).
Reporting of installed or context dependencies
These software/hardware dependencies are not related in any way to Artifacts contained in Software Modules. Artifacts and SoftwareModules in Bosch IoT Rollouts are only "containers" to structure updates and give no information about what is really inside.
As a minimum a Software/Hardware-Dependency is described as group/vendor, name and version.
In case of reporting context dependencies, it is strongly recommended to also classify the dependency with a type specifier (e.g. "hw-part", "JRE"...). The definition of the type is not enforced anywhere but if appropriate we recommend to use one of the recommendations below.
In case of installed dependencies, usually the backend systems will default to the softwareModuleType of the SoftwareUpdatable feature as type when ommitted.
Recommended dependency description patterns
These dependencies are currently not directly required by Bosch IoT Rollouts but are used by a currently (experimental) complex dependency management, which provides additional support for packaging or server-side compatibility checks.
Within Ditto/ Bosch IoT Things the special characters "/" is not allowed. In such cases the URL encoding according to RFC 3986, ("%2F") has to be used when building the "key" of the dependency entry.
We recommend not using spaces.
|
GROUP |
NAME |
VERSION(pattern) |
TYPE |
comments |
JDKs |
openjdk |
jre |
11 |
JRE |
|
|
openjdk |
jre |
8 |
|
|
Hardware parts |
<group/vendor/part> |
<part-name/property> |
<value/serial-no> |
hw-part |
|
|
system.cpu |
vendor_id |
GenuineIntel |
hw-part |
|
|
system.cpu |
architecture |
x86_64 | arm64 | arm32 |
hw-part |
|
|
com.bosch |
breakpad-front-left |
4711-123-345 |
hw-part |
|
Snaps |
<Publisher> |
<name> |
<version> |
snap |
|
|
microsoft |
teams |
28.12 |
snap |
|
OCI:Images or docker images |
<repository> |
<name> |
<tag> |
oci:image or docker:image or image |
image = docker:image |
|
docker.io/library |
hello-world |
latest |
docker:image |
|
OCI:Container or docker container |
<repository>/<image-name> |
<container-id> |
<tag> |
oci:container or docker:container or container |
container = docker:container |
|
docker.io/library/hello-world |
XXXX8c49-020e-46b4-8efa-8d3f7804639a |
latest |
|
|
Firmware/OS |
vendor |
name |
version |
firmware or os |
|
|
BOSCH |
ROS |
14.0 |
os |
|
|
odroid |
ubuntu |
14.4 |
os |
|
|
BoschSensorTec |
firmware |
47.11 |
firmware |
|
JSON example (container):
[
...,
"docker.io%2Flibrary%2Fhello-world.XXXX8c49-020e-46b4-8efa-8d3f7804639a:latest"
:
{
"group"
:
"docker.io/library/hello-world"
,
"name"
:
"XXXX8c49-020e-46b4-8efa-8d3f7804639a"
,
"version"
:
"latest"
"type"
:
"container"
},
...
]
Removing features (remove-operations)
The SoftwareUpdatable feature provides optional operations which allow the removal of installed software. This is usually not supported by all SoftwareUpdatable feature implementations, as for example an operating system/firmware is not removable.
In case of connectivity support (e.g. Zigbee, One-wire, Phillps Hue, Z-wave) or bought or rented applications (e.g. smart farming appliances) this could make sense in order to free up system resources.
DependencyDescriptions
In order to address a feature to be removed the DependencyDescription is used. The SoftwareModule is not usable to address a certain feature contained (maybe in a zip-file) in a software module.
Whether a dependency is removable at all is decided on the device, but the domain know-how on the server-side should already avoid to send remove requests which do not have a chance to be fulfilled.
Remove requests and operation status updates
One remove request may contain multiple dependency descriptions.
The remove request is tracked in the same way as the install request with the help of a correlationId.
Also the device reports the success/progress/failure in the same way by updating the operaton status property in the SoftwareUpdatable feature.
Instead of referencing the SoftwareModule by name and id, the operation status should contain the dependency descriptions which it relates to.
Success
When all dependencies are successfully removed, the operation status should be finally updated to FINISHED_SUCCESS.
All failed
In case that the request could be handled atomically, meaning all-or-nothing, this could be realized by the implementation on the device. In case that at least one dependency could not be removed, the final status should be FINISHED_ERROR.
Some failed / some succeeded
There should be at least one status update with FINISHED_ERROR and the dependency list in the operation status should contain only the dependencies which did not succeed.
For the successful removals there should be additional FINISHED_SUCCESS messages containing the dependencies where the removal succeeded.
Fail fast
It is a good practice to sort the dependencies in the remove operation in a sequence, so that the ones with a dependency on other dependencies come first on the list. So if one removal is not successful, it is likely that the other removals will also not be successfull.
Therefore, it is recommended to return a FINISHED_ERROR for the first non-successful and a FINISHED_REJECTED for the rest of the dependencies on the list.
This behavior can be overwritten (try to remove all even though there are errors) by providing a forced=true in the remove operation (note that forced=true also means not to get user/device owner feedback for the remove operation).
Status REMOVED
The REMOVED status is treated as FINSHED_SUCCESS.
Intermediate status responses
If some removals are in a "waiting" state – but not all – the REMOVING_WAITING can also address only the dependencies which are pending. Same is true for REMOVING status updates - which can be used to provide more details about the progress to the issuer of the command.