Skip to main content

Over-the-Air (OTA) Firmware Update

The most sought after Golioth feature is Over-the-Air firmware update (OTA). The ability to update firmware is crucial to building a robust and reliable IoT fleet. This is built into the Golioth SDK and the golioth_basics sample we ran on the previous page includes this feature. Let's try it out!

Overview

On this page we'll cover four steps to completing an OTA update:

  • Change the version number in the sourcecode and build the binary
  • Upload the binary to Golioth as a new Package
  • Assign the device(s) to a Cohort
  • Deploy the package to the device(s)

Update version number and build firmware

The golioth_basics sample uses a common file located at golioth-firmware-sdk/examples/common/golioth_basics.c. Edit this file, updating the version number to 1.2.6. For fun, also change the tag name to golioth_basics_new just so it's easy to see from the logging messages that a new firmware version is running.

changes to: golioth-firmware-sdk/examples/common/golioth_basics.c
LOG_TAG_DEFINE(golioth_basics_new);

// Current firmware version
static const char* _current_version = "1.2.6";

Now return to the golioth-firmware-sdk/examples/esp_idf/golioth_basics folder and rebuild the example.

idf.py build
Don't flash the ESP32!

Remember, do not use the idf.py flash command this time. We will be uploading the new binary to the device over WiFi.

After running the build command, your new binary will be located at build/golioth_basics.bin.

Upload the binary to Golioth and deploy it to your device

1. Create a Package

The Golioth Cloud represents upgradeable software components as "Packages". In the OTA example code, the package for the application firmware is called "main", so we'll need to create a corresponding package in the Golioth Console.

In the Golioth Console, go to Firmware Updates→Packages on the left sidebar and click the Create button. Set the name of the package to main, and optionally add a short description.

Create a package in the Golioth Console

2. Upload the firmware binary

Now that we have created our package, we can upload the firmware binary as the first version of main. Open the main package in the list of packages, and click New Version.

Upload an artifact in the Golioth
Console

  • Set the Artifact Version to 1.2.6 (to match what was compiled into the firmware)
  • Click the upload button in the middle of the window and choose your golioth_basics.bin file.
  • Click the Upload Artifact button to finish creating an artifact.

3. Assign the device to a Cohort

To enroll your device into Golioth's OTA update system, you need to assign it to a Cohort. Cohorts are groups of devices that have the same firmware and receive the same OTA updates.

First, we need to create a new Cohort for this device type. In the Golioth Console, go to Firmware Updates→Cohorts in the left sidebar and click the Create button. Select a name for your Cohort and click Create.

Next, we need to assign our device to this new Cohort. In the Cohort page, click Add Devices, and find your device in the list. Click the Add button on the right hand side of the device to assign it to the Cohort.

Assign device to a Cohort in the Golioth
Console

4. Create a deployment

OTA updates are rolled out to a Cohort as Deployments. To start a new update for our device, go to the Cohort's page in the Golioth Console and click Deploy. Add the main package to the deployment, and make sure it's set to version 1.2.6. You can optionally pick a name for your deployment.

Create a Deployment in the Golioth
Console

Click Next to review your deployment, then Start Deployment to start the update.

Observe the OTA firmware update

In the terminal window you see the ESP32 almost immediately recognizes that new firmware is available:

I (175827) golioth_basics: Sending hello! 17
I (185007) golioth_fw_update: Received OTA manifest
I (185007) golioth_fw_update: Current version = 1.2.5, Target version = 1.2.6
I (185017) golioth_fw_update: State = Downloading
I (185317) golioth_fw_update: Image size = 1211744
I (185327) golioth_fw_update: Getting block index 0 (1/1184)
I (185827) golioth_basics: Sending hello! 18
W (187867) golioth_coap_client: CoAP message retransmitted
I (187947) fw_update_esp_idf: Writing to partition subtype 17 at offset 0x1a0000
I (187947) fw_update_esp_idf: Erasing flash
I (191627) golioth_fw_update: Getting block index 1 (2/1184)
I (191837) golioth_fw_update: Getting block index 2 (3/1184)
I (192037) golioth_fw_update: Getting block index 3 (4/1184)
I (192187) golioth_fw_update: Getting block index 4 (5/1184)
I (192447) golioth_fw_update: Getting block index 5 (6/1184)
I (192597) golioth_fw_update: Getting block index 6 (7/1184)
... snip ...
I (279837) golioth_fw_update: Getting block index 1181 (1182/1184)
I (280107) golioth_fw_update: Getting block index 1182 (1183/1184)
I (280317) golioth_fw_update: Getting block index 1183 (1184/1184)
I (280457) golioth_fw_update: Total bytes written: 1211760
I (280467) esp_image: segment 0: paddr=001a0020 vaddr=3f400020 size=29df0h (171504) map
I (280527) esp_image: segment 1: paddr=001c9e18 vaddr=3ffbdb60 size=05868h ( 22632)
I (280537) esp_image: segment 2: paddr=001cf688 vaddr=40080000 size=00990h ( 2448)
I (280547) esp_image: segment 3: paddr=001d0020 vaddr=400d0020 size=d9a64h (891492) map
I (280847) esp_image: segment 4: paddr=002a9a8c vaddr=40080990 size=1e2a0h (123552)
I (280887) esp_image: segment 5: paddr=002c7d34 vaddr=50000000 size=00010h ( 16)
I (280887) golioth_fw_update: State = Downloaded
I (281127) golioth_fw_update: State = Updating
I (281327) fw_update_esp_idf: Setting boot partition
I (281337) esp_image: segment 0: paddr=001a0020 vaddr=3f400020 size=29df0h (171504) map
I (281397) esp_image: segment 1: paddr=001c9e18 vaddr=3ffbdb60 size=05868h ( 22632)
I (281417) esp_image: segment 2: paddr=001cf688 vaddr=40080000 size=00990h ( 2448)
I (281417) esp_image: segment 3: paddr=001d0020 vaddr=400d0020 size=d9a64h (891492) map
I (281717) esp_image: segment 4: paddr=002a9a8c vaddr=40080990 size=1e2a0h (123552)
I (281757) esp_image: segment 5: paddr=002c7d34 vaddr=50000000 size=00010h ( 16)
I (281827) golioth_fw_update: Rebooting into new image in 5 seconds
I (282827) golioth_fw_update: Rebooting into new image in 4 seconds
I (283827) golioth_fw_update: Rebooting into new image in 3 seconds
I (284827) golioth_fw_update: Rebooting into new image in 2 seconds
I (285827) golioth_fw_update: Rebooting into new image in 1 seconds
... snip ...
I (4267) esp_netif_handlers: sta ip: 192.168.1.159, mask: 255.255.255.0, gw: 192.168.1.1
I (4267) example_wifi: WiFi Connected. Got IP:192.168.1.159
I (4277) example_wifi: Connected to AP SSID: TheNewPeachRepublic
I (4287) golioth_mbox: Mbox created, bufsize: 2184, num_items: 20, item_size: 104
I (4287) golioth_basics_new: Waiting for connection to Golioth...
W (4297) wifi:<ba-add>idx:0 (ifx:0, c6:ff:d4:a8:fa:10), tid:0, ssn:1, winSize:64
I (4307) golioth_coap_client: Start CoAP session with host: coaps://coap.golioth.io
I (4307) libcoap: Setting PSK key
I (4317) golioth_coap_client: Entering CoAP I/O loop
I (4637) golioth_basics_new: Golioth client connected
I (4647) golioth_coap_client: Golioth CoAP client connected
I (4657) golioth_basics_new: Hello, Golioth!
I (4657) golioth_fw_update: Current firmware version: 1.2.6
I (4657) golioth_fw_update: Waiting for golioth client to connect before cancelling rollback
I (4677) golioth_fw_update: Firmware updated successfully!
I (4727) golioth_fw_update: State = Idle
I (5937) golioth_basics_new: Synchronously got my_int = 42
I (5937) golioth_basics_new: Entering endless loop
I (5937) golioth_basics_new: Sending hello! 0
  1. The firmware will be downloaded in blocks
  2. When the download is complete the ESP32 will reset automatically
  3. After reset, the ESP32 will connect to Golioth and confirm it is running the most recent firmware version
Log messages show the new tag name

Look closely at the terminal output and you'll see the tag name in the log messages have changed to golioth_basics_new. This is because of the change we made in the sourcecode before compiling the new firmware.

Confirm the new firmware version on the Golioth Console

After an OTA update, devices report their firmware version to Golioth.

Golioth device summary shows firmware version

Here you can see that the ESP32 is running the new version 1.2.6 firmware!