Over-the-Air Update

Over-the-Air Update

Over-the-Air (OTA) updates allow you to deploy firmware updates to one or more devices using its network connection (Ethernet, Wi-Fi, or GSM module). The image is downloaded directly from the server and flashed on the device without disruption. The update can be signed digitally for more security, so the targeted device knows if the file has been tampered with or not. You can check more information about OTA here.

Both Vitro Crystal and Vitro Shard support OTA updates. As such, it allows you to update the firmware without having physical access to the device.


Administrators currently handle OTA updates. For more information, please ask your administrator.

Vitro Crystal

To update Vitro Crystal, you will need:

  1. Vitro Crystal with Yocto-based OS.
  2. Vitro Crystal is connected to the internet.
  3. A provisioned Vitro Crystal.


To understand what provisioning is or how to do it, please check our Provisioning documentation.

  1. A valid token obtained from the administrator (or other dedicated personnel).
  2. A .swu image placed on AWS S3 bucket correctly.
    • You can find the '.swu' image for Yocto-based OS in this link. The latest version is v2.2.11, which you can download it.

If everything is set correctly, the OTA update is triggered by sending a POST request to AWS:

curl -X POST "https://core.dev.vitro.io/api/devices/<gw-id>/system/upgrade" -H  "accept: application/json" -H  "Authorization: Bearer <token>" \
-H  "Content-Type: application/json" -d "{  \"imageName\": \"<name-of-swu-file-in-s3-bucket>\"}"


If you want to learn what a POST request is, please check here.

cURL is a command-line tool for sending and receiving data; for more information, check here.

JSON syntax is used to send and receive a message. You can check what JSON is by clicking here.


  • <gw-id> is unique Crystal ID
  • <token> is token received from administrator
  • <name-of-swu-file-in-s3-bucket> is .swu file name which is placed in S3 bucket

A response message is received after the command is sent, indicating that the image update has been started. Simultaneously Crystal is sending status messages with progress information to AWS. It can be checked under IoT Core service --> Tests --> subscribe to #. Example status message:

  "status": "info",
  "token": "5fd886c5ab8c0c00063e3a6e",
  "type": "upgradeImageLink",
  "params": {
    "status": "inProgress",
    "progress": "30%",
    "message": "Progress : 30 %"


The update can take around 5 minutes to complete. When it is finished, the last status message will say that progress is at 100%.

Wait for Crystal to reboot and check if the update is successful.

Vitro Shard

Since you can have your custom application for Vitro Shard, we focus on our API in this documentation. Either way, you can always update the firmware with a dedicated programmer, but you need physical access to the device and programming pins.

Therefore, to perform an OTA update to Vitreo Shard, a CAN connection between Vitro Shard and Vitro Crystal is required, Vitro Crystal and Vitro Shard need to be provisioned, and Vitro Crystal must have an internet connection. The update is triggered remotely by a person with appropriate permissions, but the update per se is entirely handled by Vitro Crystal and Vitro Shard by themselves.


For an uninterrupted update, there are two applications (one being a copy of the other). We call them applications A and B. When app A is being updated, app B takes over and vice-versa. For more information, please check our Developers guide.

To carry out an OTA update, please follow these steps:

  1. Rebuild the application to have app_1.bin and app_b.bin binaries.
  2. Build the .swu (upgrade package) file via a dedicated script.
    • The script is located in nodes-upgrade-package/ directory and its name is build_swu_image.sh. It automatically prepares the upgrade package from already built app_a.bin and app_b.bin binary files.

As an example, the output of the script is:

nodes-upgrade-package$ ./build_swu_image.sh 0

Firmware id is: 0

Firmware version is:

Setting id in sw-description file...
Setting version in sw-description file...
Setting id in upgrade_package.json file...
Setting version in upgrade_package.json file...

Building SWU image...

498 blocks
  1. You will find the .swu file in nodes-upgrade-package/bin directory.
  2. Send the file to AWS S3.
  3. Trigger the update by doing a POST request:
curl -X POST "https://core.dev.vitro.io/api/devices/<crystal-id>/nodes/upgrade" -H  "accept: application/json" -H "Authorization: Bearer <access-token>" -H  "Content-Type: application/json" -d "{  \"force\": true,  \"packageName\": \"<swu-package-name>\"}"


  • <crystal-id> must be replaced with correct your Crystal ID.
  • <access-token> is a temporary token, and it is obtained from an administrator.
  • <swu-package-name> is the package name placed in AWS S3.
  1. Done! The OTA has started. You can verify the status of the update by checking the Vitro Shard's output (UART). The output should look like this:
[INFO][UPGRADE CONTROLLER]: Handle upgrade request to firmware id 258 of version:

(...) ~300 seconds later

[INFO][UPGRADE CONTROLLER]: Verifying flashed upgrade data
[INFO][UPGRADE CONTROLLER]: Upgrade data verified successfully
[INFO][NODE CONTROLLER]: New firmware available
[INFO][ENVIRONMENT INTERFACE]: Data saved in flash memory successfully
[INFO][NODE CONTROLLER]: Performing software reset...
[INFO][MEASUREMENT API]: Reading values
[INFO][CANBUS]: Constructed with external event queue 0x20000e04
[INFO][FLASH INTERFACE]: Initialized successfully
[INFO][ENVIRONMENT INTERFACE]: Initialized successfully
[INFO][UPGRADE CONTROLLER]: Initialized successfully
[INFO][NODE CONTROLLER]: Boot after upgrade
[INFO][ENVIRONMENT INTERFACE]: Data saved in flash memory successfully
[INFO][NODE CONTROLLER]: Initialized successfully with external event queue 0x20000e04
[INFO][MEASUREMENT API]: Constructed with external event queue 0x200019f8
[INFO][MAIN]: Application started; (id: 0) v2.1.1.0; vitroio-sdk v1.2.1
[INFO][SHARD_EDGE]: I2C3 is disabled. Configuring ADC1 and ADC2.
[INFO][SHARD_EDGE]: UART_USER is disabled. Configuring ADC3 and ADC4.
[INFO][SHARD_EDGE]: SPI1 is disabled. Configuring ADC_CL1, ADC_CL2, ADC_CL3 and ADC_CL4.
[INFO][SHARD_EDGE]: UART_RS232 is disabled.
[INFO][SHARD_EDGE]: Final IOExpander 001 Port 0 state = ff
[INFO][SHARD_EDGE]: Final IOExpander 001 Port 1 state = af
[INFO][SHARD_EDGE]: Final IOExpander 010 Port 0 state = 77
[INFO][SHARD_EDGE]: Final IOExpander 010 Port 1 state = 77
[INFO][NODE CONTROLLER]: Initializing communication
[INFO][NODE CONTROLLER]: Node ID response frame handled
[INFO][NODE CONTROLLER]: Node ID was assigned: 0x3
[INFO][NODE CONTROLLER]: frameData: 40408000
[INFO][NODE CONTROLLER]: Communication was initialized successfully; Node ID: 0x3
[INFO][MEASUREMENT API]: Set poll time 10 s
[INFO][MEASUREMENT API]: Registered sensor 0x20000da0

The above log indicates that the update has been performed correctly. Shard should reset itself and start running a new application.

What’s Next