Bosch IoT Device Management

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

images/inline/5ebdda0d98cabb69393492d31d13304801491932.png

Feature and entities contained in the feature

SoftwareUpdatable

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".

images/confluence/s/-85fg30/8703/zb070w/_/images/icons/emoticons/warning.svg It must be ensured, that one thing has only one SoftwareUpdatable feature responsible for a softwareModuleType

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:

  • For a SoftwareUpdatable feature which is managing docker-containers this would be the list of installed docker-containers.

  • For a feature which is managing the operation-system itself, this list would contain only one entry with probably the vendor and/or name and current version of the OS like "ubuntu:20.20".

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.

OperationStatus

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

DependencyDescription

optional

In the case of a remove operation status, the currently processed software

Can be used to indicate the currently removed software.

DependencyDescription

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.

SoftwareUpdateAction

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

SoftwareModuleAction

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.

SoftwareArtifactAction

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.

Links

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.

SoftwareRemoveAction

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.

images/inline/a87322abdcdec5f0f706def9ae9516f19397e5da.png

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:

  1. 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 installed

  2. Without 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 Rollouts

  3. Using 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:

  1. Create a campaign per hardware revision
    Device version could be either identified by:

    1. Selecting a property/attribute in the device-thing representing the HW version (if the user knows a unique identifier here)

    2. Selecting a value out of the contextDependencies - a property which is exactly meant to enable the device to announce such information

    3. Having sorted the devices in a group or having them tagged according to the version of the driver which needs to get assigned.

  2. 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

  1. A Device is created in Bosch IoT Manager/Things/Hub via the Device Provisioning API or the Bosch IoT Suite Console

  2. The Device connects and reports its current state by creating features in Bosch IoT Things:

    1. 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.

    2. 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.

  3. 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

  1. A user of Bosch IoT Rollouts creates one or more Software Modules in Bosch IoT Rollouts

  2. 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, ....

  3. 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).

  4. 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

  5. The campaign can now been started.

Running the campaign

  1. A campaign/rollout will generate one or more respective rules in the Mass Management Engine which is part of Bosch IoT Manager.

  2. 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).

  3. 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)

  4. 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


images/inline/bb96d3bacc75acbb69f5679397ca47163b8fbc9e.png

Removing software and cancel remove

images/inline/b6253dda904e9a2a549997caced818f1dd29f05d.png

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.