---
# System prepended metadata

title: OTA Updates
tags: [ServicePleX]

---

# ServicePleX OTA Updates

**ServicePleX** OTA Updates involves uploading the file to the cloud and assigning the firmware to the device you want to update.

![image](https://hackmd.io/_uploads/BkqrnDfdp.png)

[toc]

## ServicePleX side

### OTA setup

1. Sign in to the **ServicePleX** web console
2. In the left navigation panel, choose **Advanced features**, choose **OTA updates**, and then click **Add Package**.
3. Enter a Title, Version, Device profile, Package Type and Upload binary file.
4. Click **Add**.
5. Once package is added, In the left navigation panel go to  **Entities**, **Devices**.
6. Select the Device (e.g. **CIM-168-02-22-90**) you want to send an OTA update.
7. **Edit** the Device and Assign Firmware.
8. Select **Apply** changes.

![image](https://hackmd.io/_uploads/rk8F4D5O6.png)


## Device side

### MQTT Device API 

#### Why shared attributes?
  * Control application behavior
  * Subscribe to server-side changes
  * **OTA firmware updates**
    ![image](https://hackmd.io/_uploads/SJyeUWrF6.png)
#### Attributes API
  ``ServicePleX`` attributes API allows devices to
  * Upload client-side device attributes to the server
    :::spoiler details
    In order to publish client-side device attributes to the server, send PUBLISH message to the following topic:

    ``v1/devices/me/attributes``
    :::
  * Request client-side and shared device attributes from the server
    :::spoiler details
    In order to request client-side or shared device attributes to the server, send PUBLISH message to the following topic:

    ``v1/devices/me/attributes/request/$request_id``
    where $request_id is your integer request identifier. Before sending PUBLISH message with the request, client need to subscribe to
    ``v1/devices/me/attributes/response/+``
    :::
  * Subscribe to shared device attributes from the server
    :::spoiler details
    In order to subscribe to shared device attribute changes, send SUBSCRIBE message to the following topic:
    ``v1/devices/me/attributes``
    :::
#### Firmware API
When ``ServicePleX`` initiates an MQTT device firmware update, it sets the **fw_version**, **fw_title**, **fw_tag**, **fw_size**, **fw_checksum_algorithm**, **fw_checksum** shared attributes. In order to receive the shared attribute updates, the device has to subscribe to 
  ``v1/devices/me/attributes/response/+``

  Where
  \+ is the Wildcard character.

  When the MQTT device receives updates for fw_title and fw_version shared attributes, it has to send PUBLISH message to ``v2/fw/request/${requestId}/chunk/${chunkIndex} ``

  Where
    ${requestId} - number corresponding to the number of firmware updates. The ${requestId} has to be different for each firmware update.
    ${chunkIndex} - number corresponding to the index of firmware chunks. The ${chunkID} are counted from 0. The device must increment the chunk index for each request until the received chunk size is zero.
    And the MQTT payload should be the size of the firmware chunk in bytes.
    For each new firmware update, you need to change the request ID and subscribe to
  ``v2/fw/response/+/chunk/+``

  Where
  \+ is the Wildcard character.

##### Sequence Diagram
  
  * **Part I**
  ```plantuml
    @startuml

    == Send to current firmware status to the server ==

    Device -> Server: Telemetry update (**MQTT, PUBLISH**) \nTopic: **v1/devices/me/telemetry** \nPayload: {"current_fw_title":"CIM-168","current_fw_version":"1.0.0"}

    == Subscribe to shared attribute response from the server ==

    Device -> Server: subscribe to attribute response (**MQTT, SUBSCRIBE**) \nTopic: **v1/devices/me/attributes/response/+**  

    == Request shared attributes from the server ==

    Device -> Server: request attribute values from the server (**MQTT, PUBLISH**) \nTopic:**v1/devices/me/attributes/request/$request_id** \nPayload: {"sharedKeys":"fw_title,fw_version,fw_size,\nfw_checksum,fw_checksum_algorithm"}

    Device <-- Server: receive response (**MQTT, PUBLISH**)\nTopic: **v1/devices/me/attributes/response/$request_id** \nPayload:{"shared":{"fw_title":"CIM-168",\n"fw_version":"1.0.1", "fw_size":3735576,\n"fw_checksum_algorithm":"SHA256",\n"fw_checksum":"ef52eebab2446b8b8179798e0d14517e1b9321cff93debe55d79b4460bc51335"}}

    == Subscribe to attribute updates from the server ==

    Device -> Server: Subscribe to attribute response(**MQTT, SUBSCRIBE**)\nTopic: **v1/devices/me/attributes/**

    == Receive the attribute update from the server ==
    Device <-- Server: receive attribute update from the server (**MQTT, PUBLISH**)\nTopic:**v1/devices/me/attributes/**Payload:{"fw_title":"CIM-168",\n "fw_version":"1.0.1", "fw_size":3735576,\n "fw_checksum_algorithm":"SHA256",\n "fw_checksum":"ef52eebab2446b8b8179798e0d14517e1b9321cff93debe55d79b4460bc51335"}
    @enduml
  ```
  * **Part II (p.s. replace 8192 with your chunk size)**
  ```plantuml
    @startuml

    == Send to current firmware status (DOWNLOADING) to the server ==

    Device -> Server: Telemetry update (**MQTT, PUBLISH**) \nTopic: **v1/devices/me/telemetry** \nPayload: {"current_fw_title":"CIM-168","current_fw_version":"1.0.0","fw_state":"DOWNLOADING"}

    == Subscribe to firmware chunk response from the server ==

    Device -> Server: subscribe to firmware chunk response (**MQTT, SUBSCRIBE**) \nTopic: **v2/fw/response/+/chunk/+**  

    == Request firmware chunk from the server ==

    Device -> Server: request firmware chunk from the server (**MQTT, PUBLISH**) \nTopic:**v2/fw/chunk/request/${requestId}/chunk/${chunkIndex}** \nPayload: 8192

    Server -> Device: receive response (**MQTT, PUBLISH**) \nTopic: **v2/fw/response/${requestId}/chunk/${chunkIndex}** \nPayload: *firmware binary data*

    Device <-> Server: ...

    == Send current firmware status to the server ==

    Device -> Server: Telemetry update (**MQTT, PUBLISH**) \nTopic: **v1/devices/me/telemetry** \nPayload: {"current_fw_title":"CIM-168","current_fw_version":"1.0.0","fw_state":"DOWNLOADED"}
    Device -> Server: Telemetry update (**MQTT, PUBLISH**) \nTopic: **v1/devices/me/telemetry** \nPayload: {"current_fw_title":"CIM-168","current_fw_version":"1.0.0","fw_state":"VERIFIED"}
    Device -> Server: Telemetry update (**MQTT, PUBLISH**) \nTopic: **v1/devices/me/telemetry** \nPayload: {"current_fw_title":"CIM-168","current_fw_version":"1.0.0","fw_state":"UPDATING"}
    Device -> Server: Telemetry update (**MQTT, PUBLISH**) \nTopic: **v1/devices/me/telemetry** \nPayload: {"current_fw_title":"CIM-168","current_fw_version":"1.0.1","fw_state":"UPDATED"}
    
    @enduml
  ```
##### Example: MQTTX 

* Subscribe to shared attribute response from the server (**JSON payload without any additional spaces**)
  `` {"sharedKeys":"fw_title,fw_version,fw_size,fw_checksum,fw_checksum_algorithm"}
  ``
  ![image](https://hackmd.io/_uploads/Hy9RHf0u6.png)

:::spoiler References
## References

* [ThingsBoard OTA Updates](https://buildstorm.com/blog/thingsboard-ota-updates/)
* [Edge Insights for Autonomous Mobile Robots (EI for AMR) Developer Guide](https://www.intel.com/content/www/us/en/docs/ei-for-amr/developer-guide/2022-3-1/ota-updates.html)
* [Firmware API](https://avantec-thingsboard.readthedocs.io/en/latest/thingsboard/thingsboard-mqtt-device-api.html#firmware-api)
* [ThingsBoard MQTT Device API](https://avantec-thingsboard.readthedocs.io/en/latest/thingsboard/thingsboard-mqtt-device-api.html)
:::
