Last week we announced the open beta for Golioth Bluetooth support. It makes connecting your BLE IoT fleet to the Internet a snap, for bi-directional data and OTA firmware updates. Today I’ll show how easy it is to use this service to a control the fleet all at once, or to drill down to individual unit by using the built-in Settings service.
Apply settings to all or one
The Golioth Settings service delivers fleet control from the cloud down to devices. For example, let’s consider Bluetooth (BLE) devices that sleep most of the time but occasionally wakes up to upload sensor data via a gateway. The amount of time spent in the sleep state can be added as a setting that applies to the entire fleet, but the same setting may also be tweaked on a device-by-device basis.
If you know your entire fleet is going to be collecting more sensor data than usual, you can make one change and all devices will update their sleep pattern the next time they check in. In the same way, the setting for a single device may be adjusted separately from the fleet-wide setting.
Since this is built into the Golioth platform, its really easy to add it to your Bluetooth firmware. Let’s see what is involved in adding a new setting.
Prerequisite: Run the sample application
If you don’t already have a Bluetooth fleet on Golioth, follow the Getting Started guide in the Bluetooth Gateway repository and add a leaf-node by following the example app in the Pouch repository. This will get you up and streaming simulated sensor data to the cloud in no time. Golioth is free for individuals making it frictionless to take it for a test-drive. You will need to get hardware that matches the recommended boards for the lowest-friction experience.
The sample Pouch application already supports the Settings service to switch an LED on or off remotely. From the cloud, this is just a few clicks to add a boolean setting called LED
.
The device-side code that supports this setting couldn’t be easier. It’s made up of a function that will run as a callback, and a macro to register that callback.
static int led_setting_cb(bool new_value) { LOG_INF("Received LED setting: %d", (int) new_value); if (DT_HAS_ALIAS(led0)) { gpio_pin_set_dt(&led, new_value ? 1 : 0); } return 0; } GOLIOTH_SETTINGS_HANDLER(LED, led_setting_cb);
The important parts are the first and last lines of the code segment above. The first line is a function declaration that follows the callback function prototypes specified in the Pouch library. In this case we know the callback is for a Setting of boolean type because that’s the type for the parameter passed into this function. The last line is important because it registers this callback. The parameters used in that registration are the settings name that will trigger the callback (LED
) and the function to run when that setting is received.
The code inside the actual function is up to you. In this example, the new setting is logged. Next the function checks to see if there is an LED enabled in the devicetree, toggling it when found. I suppose I said there are only two important parts, but the return code is also important. Whether successful or not, the return code will be reported back to the cloud, indicating that the device successfully (or unsuccessfully) received the settings update.
Lets try adding our own setting to the fleet.
Adding a setting to send text to the Bluetooth fleet
If your Bluetooth IoT devices have a user interface, like a screen, you may want to send messages to them. Lets add a setting that sends a string to the fleet. First, add the setting in the Golioth web console.
The screenshot above shows a setting called MESSAGE added as a String type. The value is the string that should initially be sent to the fleet. The value may be changed at any time (although the key and data type are immutable because they need to match what is built into the firmware).
Adding this setting to the firmware is nearly the same as we saw in the previous section, requiring a callback function that is then registered for this setting.
#include <golioth/settings_callbacks.h> #define MESSAGE_MAX_LEN 64 char _stored_msg[MESSAGE_MAX_LEN + 1]; static int settings_message_cb(const char *new_value, size_t len) { if (MESSAGE_MAX_LEN < len) { LOG_ERR("Received message is too long: %zu > %u", len, MESSAGE_MAX_LEN); return -1; } if (0 == memcmp(_stored_msg, new_value, len)) { return 0; } LOG_DBG("New MESSAGE setting: %.*s", len, new_value); snprintk(_stored_msg, MESSAGE_MAX_LEN, "%.*s", len, new_value); scroll_message(led_dev, _stored_msg, 50); return 0; } GOLIOTH_SETTINGS_HANDLER(MESSAGE, settings_message_cb);
For completeness I’ve included all the code needed by this callback. We see the header file that contains the typedefs for the callback functions. Next there is a character array declared globally to store the most recently received message.
I chose to illustrate this callback because a string setting is slightly different from the other types (bool, int, float) because it passes both a pointer to the string and a length. The callback function checks to see if the string is too long, before copying it to the global array and logging the new message. This happens to also push the message to an LED matrix on the demo device.
Despite a few differences, this continues to be extremely easy to implement. Once the device is in the field, you can drill down to control a single member of the fleet from the settings tab of its device page.

Data Up, Settings and OTA Update Down
Golioth Connectivity enables a new generation of Bluetooth devices that can send any data they like to the cloud. At the same time, you can control your fleet using the Settings service, and update the leaf nodes using the OTA service. We’re happy to welcome the world of Bluetooth devices properly to the Internet, and its ready for you to start using right now!
No comments yet! Start the discussion at forum.golioth.io