====== IoT9: BLE Communication with notify/indicate ===== This scenario presents how to extend the Bluetooth Low Energy server and client devices with a notification/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. Notification and indication methods of data transmission should be known. We will use in this scenario the knowledge of the services and characteristics so making the [[en:iot-open:practical:hardware:sut:esp32:IoT_8]] exercise is recommended. ===== Suggested Readings and Knowledge Resources ===== * [[en:iot-open:introductiontoembeddedprogramming2:cppfundamentals]] * [[en:iot-open:hardware2:esp32|]] * [[en:iot-open:practical:hardware:sut:esp32|]] ===== 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 [[en:iot-open:practical:hardware:sut:esp32:IoT_8]]. ==== Task to be implemented ==== **Task 1.** Implement a program that operates as the BLE server which advertises itself and allows us to connect to. After a successful connection, it handles the notify descriptor modification and sends the data automatically if notifications are enabled. \\ **Task 2.** Implement a client device, capable of connecting to the server, enabling notifications and displaying the exemplary data coming from a server as notification packets. ==== Start ==== You can use the simple client and server programs from [[en:iot-open:practical:hardware:sut:esp32:IoT_8]] 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 [[en:iot-open:practical:hardware:sut:esp32:IoT_8]]. We will configure this characteristic as notify/indicate capable. It allows us to establish a connection and, if successfully connected, enable the indication or notification 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 [[en:iot-open:practical:hardware:sut:esp32:IoT_8]] by including the BLE2902.h library which handles the Client Characteristic Configuration Descriptor (CCCD). The descriptor of this type is used to enable or disable the notification and indication feature. ^ Descriptor UUID ^ Bits 1 and 0 ^ CCCD value ^ Function ^ | 0x2902 | 00 | 0 | notify/indicate disabled | | ::: | 01 | 1 | enable notification | | ::: | 10 | 2 | enable indication | #include "BLE2902.h" Next, we add 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. BLECharacteristic *pNotifyCharacteristic; //class for the characteristic #define NOTIFY_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86" We create an additional characteristic with reading, writing, notify and indicate enabled, and the initial text "00" as a placeholder for the data. We also add the descriptor to the characteristic. // Create a BLE Characteristic pNotifyCharacteristic = pService->createCharacteristic( NOTIFY_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE ); pNotifyCharacteristic->setValue("0"); // Create a BLE Descriptor pNotifyCharacteristic->addDescriptor(new BLE2902()); Any characteristic can be configured as notify or indicate enabled. We can enable this mechanism for more than one characteristic. After these modifications, it would be possible to observe an additional characteristic in the service with the possibility of reading, writing, and enabling notification and indication. === Step 2 === At this step, we implement periodical data sending. We add two variables, an integer for holding the value incremented every loop pass and a text value converted from an integer to be sent within the indication/notification packet. int int_value=0; char text_value[] = "000000"; In the loop() function we modify the part executed if the connection was established. We'll add conversion from integer to text with atoi(), an update of characteristic value, and an incrementation of integer value. void loop(){ if (!deviceConnected && !advStarted) { pServer->startAdvertising(); // restart advertising advStarted = true; } if (deviceConnected){ advStarted = false; itoa(int_value,text_value,10); pNotifyCharacteristic->setValue(text_value); pNotifyCharacteristic->notify(); int_value++; } delay(500); }; === Step 3 === In this step, we'll analyse the communication between the server and the client. The client software is much more complex than the server. Some parts of the client 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. {{ en:iot-open:practical:hardware:sut:esp32:ble_client.drawio.svg?500 |The client algorithm}} === Step 4 === We have to extend the client software from scenario [[en:iot-open:practical:hardware:sut:esp32:IoT_8]] with some elements. Let's start with adding another remote characteristic which is responsible for receiving notifications. #define REMOTE_NOTIFY_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86" In the function for connecting to the server, we have to add another characteristic and register the callback function. It is also good to clear the LCD after establishing a connection. // Obtain a reference to the notify characteristic of the chosen service. pRemoteNotifyCharacteristic = pRemoteService->getCharacteristic(BLEUUID(REMOTE_NOTIFY_CHARACTERISTIC_UUID)); if(pRemoteNotifyCharacteristic->canNotify()) pRemoteNotifyCharacteristic->registerForNotify(notifyCallback); lcd.clear(); Next, we add the callback function which will be called every time the server sends a new notification packet. static void notifyCallback( BLERemoteCharacteristic* pBLERemoteNotifyCharacteristic, uint8_t* pData, size_t length, bool isNotify) { lcd.setCursor(0,0); pData[length]=0; //limit the length of the printed string lcd.print((char*)pData); } You can leave a periodical reading of the second characteristic in the loop(), but you will observe that sometimes its value appears together with the notification in the first line of the LCD. This is because notification callback is called as the interrupt handler, and can be executed between setting the cursor and displaying the characteristic value. The only way to avoid it is to move displaying of incoming notifications to the mail loop. ==== Result validation ==== You should be able to establish a connection and read the non-notification characteristic data. After enabling the notification we will observe periodic incrementation of the value sent with notify data packets. You can observe that sometimes devices do not connect. This can happen because if you upload the new version of the program to one of the devices the second one remains in a connected state. In such a situation you need to restart both devices. ===== 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 ===== {{:en:iot-open:logo_iot_200_px.png?200|}}\\ 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 [[https://en.wikipedia.org/wiki/Creative_Commons_license|Creative Commons Licence]], free for Non-Commercial use.
{{:en:iot-open:ccbync.png?100|}}