Table of Contents

STM_IoT_7: BLE Communication with indications

This scenario presents how to extend the Bluetooth Low Energy server and client devices with a notification or indication mechanism for sending data automatically. If enabled, notifications or indications are sent at any time while the data in the server is updated. A difference between them is that a notification is an unacknowledged message while an indication is an acknowledged message. While one of them is enabled by the client, the server decides on the time of the message sent.

Prerequisites

It is necessary to understand the principles of the Bluetooth Low Energy protocol with concepts of services, characteristics and descriptors. We will use in this scenario the knowledge of the advertising process so making the STM_IoT_6: BLE Communication with characteristics exercise is recommended.

Suggested Readings and Knowledge Resources

Hands-on Lab Scenario

This scenario is intended to be implemented using two BLE laboratory nodes. One of them is a server, while the second is a client. Here we will present the extension of the scenario implemented in STM_IoT_6: BLE Communication with characteristics

The Nucleo STM32WB55 development boards which are used in our STM laboratory don't have the BLE firmware flashed by default. If you would like to test this scenario on your own board please refer to the STM documentation on the flashing process [1]. Read and follow the documentation carefully because of the danger of “bricking” your device.

Task to be implemented

Task 1. Implement a program that operates as the BLE server which advertises itself and allows us to connect to. We should be able to subscribe to indications of the characteristic.
Task 2. Implement a client device, capable of subscribing to the characteristic and reading the exemplary data from a server with a indication mechanism.

Start

It is advised to use the server and client programs from STM_IoT_6: BLE Communication with characteristics as the starting point.

Steps

We will pass through the lab in a few steps. We will add the second characteristic to the example from lab STM_IoT_6: BLE Communication with characteristics. We will configure this characteristic as capable of transmitting data with indication. It allows us to establish a connection and, if successfully connected, enable the indication feature. With this feature enabled, the peripheral device initiates data transmission. It can be used for periodic measurement reading or updating information on value change.

Step 1

We start with the program written during the laboratory STM_IoT_6: BLE Communication with characteristics by adding another characteristic to the service and variable required to hold the pointer to the characteristic class. We need to define the UUID for this characteristic.

#define INDICATE_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86"
 
// BLE Characteristic - custom 128-bit UUID, read and notify enabled
BLEByteCharacteristic pIndicateCharacteristic(INDICATE_CHARACTERISTIC_UUID, BLERead | BLEWrite | BLEIndicate);

In the setup() function we add a new characteristic to the service and set its initial value.

// add the characteristic to the service
pService.addCharacteristic(pIndicateCharacteristic);

// set the initial value for the characteristic:
pIndicateCharacteristic.setValue(1);

After these modifications, it would be possible to observe an additional characteristic in the service with the possibility of reading, writing, and enabling notifications.

Step 2

At this step, we implement periodical data sending. We add the counter variable, an integer for holding the value incremented every loop pass. We will increment this counter with use of millis() function to do not block the loop() with delay();

int counter = 1;
int delay_millis;

In the main loop() we implement the incrementation of the counter and updating of the characteristic.

void loop() {
  // listen for BLE peripherals to connect:
  BLE.central();
  if (millis() > delay_millis +1000){
    delay_millis = millis();
    pIndicateCharacteristic.setValue(counter);
    counter++;
  }
}

Step 3

In this step, we will analyse the behaviour of the client. The client software is much more complex than the server. It is because the server, called also the central device, in many circumstances is a more powerful device than the peripheral. Some parts of the software are implemented as callback functions because they handle reactions on the data coming asynchronously from the server. The diagram presents the algorithm of the client and data coming from the server. The client algorithm

Step 4

While we have analysed the client's behaviour we can start implementation. Let's begin with modifying the remote characteristic for receiving notifications. Notice its UUID they must match the one defined in the server.

#define REMOTE_NOTIFY_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86"
We intentionally specified here the same UUIDs as in ESP32 BLE scenarios. If both platforms are physically available in the same laboratory, you can try to connect different hardware platforms with BLE.

In a loop() function we check if a peripheral with UUID we are interested in was discovered. If so we check its name. If the remote device's name is as we expect we print its name, stop scanning, and call the function which reads and displays the value of the characteristic. This function uses the polling method of reading the updated characteristic value. While the function returns, we restart scanning.

At the time of writing this book the mechanism available for automatic update of the characteristic value was indication only. Notifications couldn't be subscribed.

We will present the full code of the function to subscribe and receive the indications. The function reads the characteristic value in some steps:

  1. Connects to the remote device.
  2. Discovers attributes of the remote service.
  3. Retrieves the characteristic with specified UUID.
  4. Checks if the remote device is properly connected.
  5. Checks if the remote characteristic can be subscribed.
  6. Subscribes to the characteristic with indication mechanism.
  7. Waits for the characteristic value update.
  8. Reads the value and displays it on LCD.
void display_characteristic(BLEDevice peripheral) {
 
  // connect to the peripheral
  if (peripheral.connect()) {
 
    // discover peripheral attributes
    if (peripheral.discoverAttributes()) {
 
      // retrieve the remote characteristic to read
      remoteCharacteristic = peripheral.characteristic(REMOTE_NOTIFY_CHARACTERISTIC_UUID);
      if (remoteCharacteristic) {
        // check if the characteristic can be read
        if (remoteCharacteristic.canSubscribe()){
          remoteCharacteristic.subscribe();
 
          // if the peripheral is connected display the value
          while (peripheral.connected()) {
 
            // check if the value was updated
            if (remoteCharacteristic.valueUpdated()) {
 
              // yes, get the value, characteristic is 1 byte so use byte value
              byte value = 0;
              remoteCharacteristic.readValue(value);
              lcd.setCursor(0,1);
              lcd.print(value);
 
            } // if (remoteCharacteristic.valueUpdated()) 
          } // while (peripheral.connected())
        } // if (remoteCharacteristic.canSubscribe())
      } // if (remoteCharacteristic)
      peripheral.disconnect();
    } // if (peripheral.discoverAttributes())
  } // if (peripheral.connect())
}

Result validation

You should be able to read the name of the remote device in the first line of the LCD. After establishing the connection, the characteristic value should appear on the display's second line.

FAQ

What is the difference between notification and indication?: As it was mentioned in the beginning the notification is an unacknowledged message while an indication is an acknowledged message. It means that if the indication message remains unacknowledged, the peripheral device won't send another message for this characteristic.
Is the notification/indication mechanism similar to interrupts?: You are right. They work in a similar manner as interrupts in the microprocessor. They allow sending the data asynchronously, and the peripheral decides about the time of the message sent like the peripheral decides on the time of signalling interrupt. Data transmission when the central device sends the packet with a characteristic read command is similar to the polling method used in microprocessors.

Project information


This Intellectual Output was implemented under the Erasmus+ KA2.
Project IOT-OPEN.EU Reloaded – Education-based strengthening of the European universities, companies and labour force in the global IoT market.
Project number: 2022-1-PL01-KA220-HED-000085090.

Erasmus+ Disclaimer
This project has been funded with support from the European Commission.
This publication reflects the views of only the author, and the Commission cannot be held responsible for any use that may be made of the information contained therein.

Copyright Notice
This content was created by the IOT-OPEN.EU Reloaded consortium, 2022,2024.
The content is Copyrighted and distributed under CC BY-NC Creative Commons Licence, free for Non-Commercial use.