Skill Level: Intermediate

More willingness to have a go than skill required

Trying out the very latest functionality of the ESP32/Arduino SDK this demonstrates how to connect Bluetooth Low Energy beacons to the Watson IoT Platform.


  1. Before you start

    Be warned, this uses bleeding edge functionality of the ESP32/Arduino SDK and API's that will certainly change. It is however an interesting and much anticiapted area of functionality so it seems worthwhile showing a working example now so you can get your hands dirty experimenting with it. 

    Note also that this will skip over the basics of connecting to the Watson IoT Platform with an ESP32/Arduino. For more help on that see the previous developerWorks article “Connect an ESP32 to the Watson IoT Platform!“.


  2. A quick introduction

    Bluetooth Low Energy provides a way for devices to broadcast small messages to nearby devices with very low power. These devices are know as BLE “beacons” and they can do interesting things such as having something happen when a device comes within proximity to a certain location, or to have battery powered sensors which can broadcast readings for years without changing a battery.

    Commonly these beacon messages are received by BLE enable devices such as smartphones but that is often not terribly convenient, for example, your temperature sensor only has its data captured when you happen to have your smartphone nearby.

    You can use custom propriety hardware and SDK's to receive and process the beacon messages but these are often expensive and/or far to complex for a non-expert to get to grips with. The Arduino functionality for the ESP32 microcontroller changes this and provides a cheap and easy to use device with both Bluetooth and WiFi capabilities which can bridge BLE beacon messages to the Internet.

  3. Scenario

    What this is going to show is how to make a BLE beacon which broadcasts a simple message, and a BLE-WiFi Gateway which receives the beacon messages and publishes them with MQTT to the Watson IoT Platform. You could use any other IoT platform but the Watson one is free to get started with and using its “Quickstart” service means there isn't even any sign-up required to demonstrate something running.

    This is going to have two parts:

    1. the beacon device broadcasting messages
    2. the gateway device which receives the broadcast messages and forwards them to the Internet
  4. The BLE beacon

    The test BLE beacon is a simple Arduino sketch that spends most of its time deepSleeping and waking up regularly to send a BLE advertising message which inludes a count of the number if times its woken up. I've used an ESP32 module on an adapter plate, powered by a couple of AA batteries. While asleep it uses about 5 microAmps and to wakeup – send the message – and go back to sleep takes about 120 milliseconds, so it should run for quite a long time powered by the AA's.


    You could of course use any other type of ESP32 module and the “development” style boards with built-in USB support are much easier to get going with, however the extra components included on the board mean is uses a lot more current while deep sleeping so they're not really suitable as a long term battery powered device.

    The Arduino code to run on that is in Github here, and looks like:

    #include "SimpleBLE.h"

    #define SLEEP_SECS 30

    SimpleBLE ble;

    String beaconMsg = "ESP32xx"; // the x's get overwritten

    // this variable maintained over deep sleeps
    RTC_DATA_ATTR static uint16_t wakeupCount = 0;

    void setup() {

    byte* bytes = beaconMsg.c_str();
    bytes[5] = wakeupCount;
    bytes[6] = wakeupCount >> 8;


    // a delay before shutdown otherwise the packets aren't sent completely
    // the delay required seems to depend on the payload length


    Serial.printf("Wakeup count=%i, awake for %i ms, deep sleeping for %i secs...\n",
    wakeupCount++, millis(), SLEEP_SECS);
    esp_deep_sleep(SLEEP_SECS * 1000000);

    void loop() {
    // doesn't ever get here

    You can see the Arduino code is pretty simple thanks to the SimpleBLE library. It is a little hacky though with delay and the way the sensor value is encoded into the message. This is because the current SimpleBLE library isn't really designed for this use and doesn't yet provide any way to include advertising data in the broadcast message. I expect this will change as the ESP32/Arduino API's are enhanced, but for now this gives enough to get going with for this BLE Gateway example.

    The SimpleBLE library was added to the ESP32/Arduino code on the 23 February so you need to get the ESP32/Arduino code from after then.

    If you have other Bluetooth devices that broadcast BLE advertising messages these might work with this example Gateway too. I've a “Tempo” which is a Bluetooth temperature sensor which does work, and I've included code in the Gateway to show extracting the tempo temperature readings.


  5. The BLE-Watson Gateway

    For the gateway device I've used a Sparkfun ESP32 Thing board. You could use any other type of ESP32 but the “development” style boards are easiest to get going with and they also enable easily powering the gateway from something like a USB phone charger.


    The Gateway Arduino sketch is larger and includes lots of boiler-plate Bluetooth code, so I'll only show an extract here of the more interesting parts. The complete sketch can be found in Github here.

    #include <stdint.h>
    #include <string.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include "controller.h"

    #include "bt.h"
    #include "bt_trace.h"
    #include "bt_types.h"
    #include "btm_api.h"
    #include "bta_api.h"
    #include "bta_gatt_api.h"
    #include "esp_gap_ble_api.h"
    #include "esp_gattc_api.h"
    #include "esp_gatt_defs.h"
    #include "esp_bt_main.h"

    #include <WiFi.h>
    #include <PubSubClient.h>

    //-------- Customise these values -----------
    const char* ssid = "<yourWifiSSID>";
    const char* password = "<yourWifiPassword>";

    #define ORG "quickstart" // your organization or "quickstart"
    #define DEVICE_TYPE "ESP32" // your registered device type or not used with "quickstart"
    #define DEVICE_ID "myEsp32" // use this default for quickstart or customize to your registered device id
    #define TOKEN "<yourDeviceToken>" // your device token or not used with "quickstart"
    //-------- Customise the above values --------

    char server[] = ORG "";
    char topic[] = "iot-2/evt/status/fmt/json";
    char authMethod[] = "use-token-auth";
    char token[] = TOKEN;
    char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;

    WiFiClient wifiClient;
    PubSubClient client(server, 1883, wifiClient);

    void setup() {
    if (btStart()) {

    void loop() {
    // nothing to do here

    void gotReading(uint8_t *adv_data) {
    // This is from the test ESP32 beacon
    uint16_t wakeupCount = (int16_t)((adv_data[11] << 8) | adv_data[10]);
    Serial.printf("My BLE device wakeup count=%i\n", wakeupCount);
    doPublish("wakeup", String(wakeupCount));

    void gotTempoReading(uint8_t *adv_data) {
    // My "Tempo" device sends min, current, and max temperature in two byte fields
    float temp = ((int16_t)((adv_data[27] << 8) | adv_data[26])) / 10.0;
    Serial.printf("My Tempo temp=%0.1f\n", temp);
    doPublish("temp", String(temp, 1));

    void doPublish(String id, String value) {
    if (!!!client.connected()) {
    Serial.print("Reconnecting client to "); Serial.println(server);
    while (!!!client.connect(clientId, authMethod, token)) {

    String payload = "{ \"d\" : { \"" + id + "\":" + value + "}}";
    Serial.print("Publishing payload: "); Serial.println(payload);

    if (client.publish(topic, (char*) payload.c_str())) {
    Serial.println("Publish ok");
    } else {
    Serial.println("Publish failed");

    void initWiFi() {
    Serial.print("Connecting to "); Serial.print(ssid);
    if (strcmp (WiFi.SSID().c_str(), ssid) != 0) {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    Serial.println(""); Serial.print("WiFi connected, IP address: "); Serial.println(WiFi.localIP());

    // remaining code from the IDF GATT Client example only change in the esp_gap_cb function...


  6. Putting it all together

    Once you've got those devices all programmed and powered on the remote Bluetooth messages should start appearing on the Watson IoT Platform Quickstart service.

    Here is what my devices look like:


    And going to the Quickstart URL – – you should see somehting like this:



  7. Conclusion

    I hope you find this an interesting and useful look at how to start experimenting with using BLE devices and the Watson IoT Platform. The beacon is presently a little unreliable, I expect due to the abuse of the SimpleBLE library, and not all of the messages end up at the Gateway, the ESP32 based Gateway appears to work well though and it successfully receives all the messages from the BLE temperature sensor device.

    I'll try to keep the example code in Github updated as the API's evolve so check back here to see how things progress. I'm also interested to hear your thoughts and if you try this how you get on so please do use the comment section below.    

6 comments on"Experiments with Bluetooth and Watson"

  1. Note that this example is presently broken when using the latest Arduino/ESP32 SDK, with the compile failing with a “Sketch too big” error. This appears to be a problem with the Arduino/ESP32 SDK and is being worked on here:

  2. I’m pretty sure the statement “wakeup – send the message – and go back to sleep takes about 120 milliseconds” is wrong. That is because it takes more than 120 milliseconds after booting commences before the user program is launched. I’m guessing the 120 milliseconds is the user program time.

    It changes the power economics a lot. In the example at the user program starts 250 milliseconds after boot and the ESP32 is pulling about 70 milliamps while awake. It may even take less energy to transmit a measurement over WIFI on the ESP8266 than it would over BLE on the ESP32 due to the long boot times. BLE bicycle cadence sensors, heart rate sensors, etc run on button batteries for months. An ESP32 BLE sensor could not do that.

    • Thanks for the comment Ken2004. Its an interesting question, I agree, and as you say it changes the power economics a lot. The 120 milliseconds I mentioned comes from the ESP32’s real time clock, so how accurate the value is will depend on where in the power on cycle the RTC is activated. As I understand it one of the slow parts of the power on / boot is loading the user code from the flash memory, and a way to avoid that is to have a smaller piece of user code in RTC memory so at each wakeup that RTC user code runs quickly and can make a decision about whether or not to continue with a full load of the user program, perhpas based on a sensor reading. There is more about this here:

  3. kahlenberg June 30, 2017

    Thanks for useful tutorial, but one question.
    Where does ESP32 send this beaconMsg over BT. Isn’t it necessarty first to “pair” ESP32 and whatsever (laptop, smartphone) over BT?

    • No its not necessary to “pair” with a BLE device. As a very simplistic description, BLE provides two types of facilities: one is the ability to advertise its presence and the other is to provide services that remote devices can “pair” with or connect to.

      Commonly the advertisements would notify peripheral devices about the services the device provided but for simple devices, like this temperature sensor, its not necessary to implement a service to get the temperature data, instead the temperature value can just be embedded in the advertising packet. Like this anything receiving the advertising packet can get the current temperature without needing to make extra requests to connect to and invoke the service. This makes the sensor device very power efficient as it doesn’t need to remain awake on the off chance that a remote device might want to connect to a service.

      BLE 4 advertising packets are quite limited so this technique only works for simple sensors which have just a few bytes of data. BLE 5 changes this making advertising packets much more powerful.

  4. Hi This code throws up errors for me gattc_client_test was not declared in this scope . I am unable to connect ESP32 as BLE gateway device but i can link to ibm bluemix using the wifi part of the code.

Join The Discussion