One of the best things about Golioth Connectivity is it makes Bluetooth devices act like all the other devices on the Golioth cloud. And one of my favorite things about Golioth is the ability to do Over-The-Air (OTA) firmware updates without any fuss. Today we’re not only going to show how the sample in our Pouch repository implements OTA, but we’ll visualize it on a development board that has a lot of LEDs and activate the firmware update using the accelerometer. Let’s dig in.
How OTA works with Pouch
Pouch is the Golioth innovation that enables Bluetooth devices to talk through standard gateways up to the Cloud and send/receive data like any other device on the cloud. It is end-to-end encrypted and can access nearly all of the same services as cellular, Wi-Fi, or Ethernet devices running the Golioth Firmware SDK. Here’s the order of events, as it works in our reference implementation:
- Bluetooth device advertises that there is data to send
- Gateway initiates connection with Bluetooth device
- Bluetooth device sends data up to the cloud (uplink)
- After uplink, available data (downlink) is sent down as a response, including services like OTA or Golioth settings
- Bluetooth device disconnects and the entire cycle can start anew, depending on the device
Note that it doesn’t need to work in that order, since many of the services in Pouch are independent of one another. Furthermore, it’s possible for you to create a completely bespoke version of the Gateway that handles Pouch traffic. But currently, our demos follow the order of events listed above.
In my setup, I am using the pre-compiled binary that is built for the NXP FRDM-RW612. Once I program that in and add Golioth credentials to the Gateway, I basically don’t need to think about it again. The Gateway logs the connections that are happening, but cannot see any of the traffic transiting through, since only the Cloud has keys paired with the Bluetooth device.

Looking at the BLE GATT sample on the Pouch repository, we can see that OTA updates are already implemented using MCUboot. The device reports its firmware version using the VERSION file in the repository:
This is used to report MCUboot firmware version at startup and to check for new available versions on the cloud. When a new version of firmware is deployed to a Cohort and the Bluetooth device checks in with the Cloud, that device will see the updated version of firmware is available as part of the downlink data. It sounds complex, but works really smoothly…let’s look at how.
Visualizing OTA updates
We have been working on a demo using the Tikk board as an asset tracker, albeit a very LED-flashy one. Part of this work was developing a wake-on-movement behavior using the accelerometer (more about that in future posts). We pulled that work and the ability to control the LED matrix on the front of the open source Tikk board. So we put that all together and what do we get? A Bluetooth device that prompts you to shake it to get an update to the OTA firmware!
Modifications
This took the standard files you see in BLE GATT demo and added some new functionality. First in the ota_manifest_receive
function, we add in some LED messaging to report the received firmware version and also clear out any previous indication of status, in case an OTA restarts.
static void ota_manifest_receive(const struct golioth_ota_manifest_component *components, size_t num_components) { char buf[32]; for (int i = 0; i < num_components; i++) { fw_size = components[i].size; LOG_DBG("Target: %s@%s, %d bytes", components[i].name, components[i].target, fw_size); LOG_HEXDUMP_DBG(components[i].target_hash, GOLIOTH_OTA_COMPONENT_HASH_BIN_LEN, "Target hash:"); if (0 != strcmp(components[i].current, components[i].target)) { golioth_ota_mark_for_download(components[i].name); } snprintk(buf,sizeof(buf),"FW ver %s ready", components[i].target); } led_message(buf); led_message("Shake to start"); clear_led_progress_bar(); }
In ota_main_receive
we see how the blocks of data are received from the cloud 1K at a time. Much like the blockwise_upload that sends data in the other direction, the total image size is split up into chunks and then tracked block by block. Since we know the current block and we know the total size, we can do some math on the progress and apply that to the 105 LEDs on the front of the Tikk board.
static void ota_main_receive(const void *data, size_t offset, size_t len, bool is_last) { LOG_DBG("Received %d bytes at offset %d", len, offset); int err = 0; if (count==0) { led_message("Starting FW update"); count++; } if (0 == offset) { err = flash_img_init(&flash_context); if (err) { LOG_ERR("Failed to init flash write"); return; } clear_led_progress_bar(); } check_progress((uint32_t)offset); err = flash_img_buffered_write(&flash_context, data, len, is_last); if (err) { LOG_ERR("Failed to write to flash: %d", err); return; } if (is_last) { err = boot_request_upgrade(BOOT_UPGRADE_PERMANENT); if (err) { LOG_ERR("Failed to request upgrade"); return; } LOG_INF("Rebooting to apply upgrade"); #if IS_ENABLED(CONFIG_LOG) while (log_process()) { } #endif led_message("Rebooting"); k_sleep(K_SECONDS(3)); sys_reboot(SYS_REBOOT_WARM); } }
At the end of the OTA process, we accept the last block and then kick off a worker to reboot the processor. This also gives us time to send one last message to the user with the LED matrix.
Try it out yourself
While the Tikk board itself is not available, you can try out OTA on your own Bluetooth devices right now. Grab one of the supported Gateway dev boards, upload the binary, program one of the supported Bluetooth nodes with a sample, and kick off an OTA within your cohort. You’ll see the device pulling down blocks and rebooting, ready to face the world with a shiny new version of firmware.
No comments yet! Start the discussion at forum.golioth.io