Simple BLE Scanner Client on ESP32

Exploration of Creating a Client: a simple Bluetooth BLE scanner that compiles a list of proximate servers, then attempts connection to each in turn. Those devices with a specific connectable service, having a specific read/write characteristic, are read from.

The example presented builds using Platformio with the espressif arduino-esp32 core, and leverages the NimBLE-Arduino Bluetooth library.

Project source code

; File: platformio.ini
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

monitor_speed=115200

lib_deps = h2zero/NimBLE-Arduino@^1.4.0
// File: main.cpp 
// ESP32_NimBLE_simple_client.
// Scan for servers, connect to any advertising a service with uuid "ABCD",
// then read from (or write to) that service's characteristic with uuid "1234".

#include <Arduino.h>

#include "NimBLEDevice.h"

void setup() { 

    Serial.begin(115200);

    // Initialise the NimBLE library, witholding any advertisable name.
    NimBLEDevice::init("");
    
    // Create a Scan(ner):
    // Get a pointer to a newly created Scan instance.
    NimBLEScan *pScan = NimBLEDevice::getScan();

    // Block whilst scanning for advertising servers, storing
    // a list of all results, over a period given in seconds,
    // or 0 (continuously).
    Serial.printf("Scanning for BLE advertisers\n");
    NimBLEScanResults results = pScan->start(10);
    Serial.printf("Found %d BLE advertisers\n", results.getCount());
    
    // Model a BLE UUID, setting the service uuid for which we'll look.
    NimBLEUUID serviceUuid("ABCD");
    
    // Iterate through the list of NimBLEAdvertisedDevice's stored
    // in the NimBLEScanResults scan results list.
    for(int i = 0; i < results.getCount(); i++) {

        // Get a pointer to the iterated Device instance.
        NimBLEAdvertisedDevice device = results.getDevice(i);
        
        // Does this iterated device advertise a service with UUID: "ABCD"?
        if (device.isAdvertisingService(serviceUuid)) {
            Serial.printf("Found a device advertising Service with UUID: ABCD\n");

            // Get a pointer to a newly created Client instance.
            NimBLEClient *pClient = NimBLEDevice::createClient();
            
            // Connect Client to iterated device.   
            if (pClient->connect(&device)) {

                // Get a pointer to the Service instance previously found.
                NimBLERemoteService *pService = pClient->getService(serviceUuid);
                
                // Did we get a pointer to the Service instance?
                if (pService != nullptr) {
                    Serial.printf("Found Service with UUID: ABCD\n");
                    
                    // Get a pointer to the Characteristic instance with UUID: "1234".
                    NimBLERemoteCharacteristic *pCharacteristic = pService->getCharacteristic("1234");
                    
                    // Did we get a pointer to the Characteristic instance we want?
                    if (pCharacteristic != nullptr) {
                        Serial.printf("Found Characteristic with UUID: 1234\n");

                        if (pCharacteristic->canRead()) {
                            Serial.printf("Characteristic is readable\n");

                            // Read the value of the Characteristic.
                            std::string value = pCharacteristic->readValue();

                            // Print the value.
                            Serial.printf("Characteristic value: %s\n", String(value.c_str()));
                        }
                    }
                }
            } else {
                // No device scanned advertises the service with characteristic we sought.
                printf("Failed to connect\n");
            }
            
            // Because simultaneous connections to Clients are possible, we abandon
            // the connection to this iterated client and reclaim it's resources.
            NimBLEDevice::deleteClient(pClient);
        }
    }
}

void loop() {

}

Serial Port Output

Output obtained when run in proximity to one BLE device flashed with the companion Simple BLE Server on ESP32.

Scanning for BLE advertisers
Found 3 BLE advertisers
Found a device advertising Service with UUID: ABCD
Found Service with UUID: ABCD
Found Characteristic with UUID: 1234
Characteristic is readable
Characteristic value: Hello BLE

Prototypical reference: https://github.com/h2zero/NimBLE-Arduino/blob/master/docs/New_user_guide.md#creating-a-client

Suggested reading: https://www.elektor.com/products/develop-your-own-bluetooth-low-energy-applications (no affiliation).


Leave a Reply

Your email address will not be published. Required fields are marked *