BLE only works when one communication is active and stays ON. Else it remains in sleep mode. Beacons are great usage of BLE. In our series of articles on Samsung Smartwatch as Proximity Switch, we have used the ESP32 as client. In this article, we are talking about using ESP32 BLE as a server. In our series of articles on Samsung Smartwatch as Proximity Switch, we discussed GATT Service and BLE characteristic. We can get the corresponding assigned numbers from the official website.
When we are thinking of BLE of a phone, then our smartwatch or smartphone first identifies it as an audio device. Usually, it also displays the battery level. It is a matter of self-understanding how a specific UUID used can provide details about the device and arrange the hierarchy to give the battery level with Service UUID. Each of the parameters can have its own UUID and these are called the Characteristic UUID. It is important to self-understand the Read, Write, Notify and Indicate capabilities by reading the official documents.
This is an example Arduino code for ESP32 which creates a BLE server that, upon receiving a connection, will send periodic notifications. Study the code how BLE Server, BLE Service, BLE Characteristic, BLE Descriptor are been handled :
---
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> BLEServer* pServer = NULL; BLECharacteristic* pCharacteristic = NULL; bool deviceConnected = false; bool oldDeviceConnected = false; uint32_t value = 0; // See the following for generating UUIDs: // https://www.uuidgenerator.net/ #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; BLEDevice::startAdvertising(); }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; } }; void setup() { Serial.begin(115200); // Create the BLE Device BLEDevice::init("ESP32"); // Create the BLE Server pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // Create the BLE Service BLEService *pService = pServer->createService(SERVICE_UUID); // Create a BLE Characteristic pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE ); // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml // Create a BLE Descriptor pCharacteristic->addDescriptor(new BLE2902()); // Start the service pService->start(); // Start advertising BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(false); pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter BLEDevice::startAdvertising(); Serial.println("Waiting a client connection to notify..."); } void loop() { // notify changed value if (deviceConnected) { pCharacteristic->setValue((uint8_t*)&value, 4); pCharacteristic->notify(); value++; delay(10); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms } // disconnecting if (!deviceConnected && oldDeviceConnected) { delay(500); // give the bluetooth stack the chance to get things ready pServer->startAdvertising(); // restart advertising Serial.println("start advertising"); oldDeviceConnected = deviceConnected; } // connecting if (deviceConnected && !oldDeviceConnected) { // do stuff here on connecting oldDeviceConnected = deviceConnected; } } |
The above code is based on Neil Kolban’s example, port to Arduino by Evandro Copercini and further update by chegewara.
For a ready to use an example of a pair of Android app and ESP32 code, first install an Android app named “BatON” from Google Play. Then you can use the below code (which was originally published by circuitdigest.com
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /*Program to use GATT service on ESP32 to send Battery Level * ESP32 works as server - Mobile as client * Program by B.Aswinth Raj * Dated on: 13-10-2018 * Website: www.circuitdigest.com */ #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> //Library to use BLE as server #include <BLE2902.h> bool _BLEClientConnected = false; #define BatteryService BLEUUID((uint16_t)0x180F) BLECharacteristic BatteryLevelCharacteristic(BLEUUID((uint16_t)0x2A19), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); BLEDescriptor BatteryLevelDescriptor(BLEUUID((uint16_t)0x2901)); class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer* pServer) { _BLEClientConnected = true; }; void onDisconnect(BLEServer* pServer) { _BLEClientConnected = false; } }; void InitBLE() { BLEDevice::init("BLE Battery"); // Create the BLE Server BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // Create the BLE Service BLEService *pBattery = pServer->createService(BatteryService); pBattery->addCharacteristic(&BatteryLevelCharacteristic); BatteryLevelDescriptor.setValue("Percentage 0 - 100"); BatteryLevelCharacteristic.addDescriptor(&BatteryLevelDescriptor); BatteryLevelCharacteristic.addDescriptor(new BLE2902()); pServer->getAdvertising()->addServiceUUID(BatteryService); pBattery->start(); // Start advertising pServer->getAdvertising()->start(); } void setup() { Serial.begin(115200); Serial.println("Battery Level Indicator - BLE"); InitBLE(); } uint8_t level = 57; void loop() { BatteryLevelCharacteristic.setValue(&level, 1); BatteryLevelCharacteristic.notify(); delay(5000); level++; Serial.println(int(level)); if (int(level)==100) level=0; } |
After uploading the code, open the Android app named “BatON”. Pair with the Bluetooth device found with the name “BLE Battery”. You’ll notice that the “BatON” will give you the (false) battery level as the code is intended to do. Above are some are practical examples of code and one app for thinking to design custom BLE things.
The unfortunate problem with many of the proprietary BLE devices is security imposed at the operating system level. As for example, you can not pair all kind of devices with a Samsung Galaxy Watch. For that reason, you will need two ESP32 (one as a server and one as a client) to get your intended work done smoothly. Anything generic app will become like “BatON” application. The official documentation for Android app can be found here and here.
Here is a good guide by Silicon Labs using Simplicity Studio for creating BLE Mobile App.
We hope that this article provided some idea around creating a BLE Android App when ESP32 used as BLE Server.