ESP32 BLE Bluetooth Examples Confuse Me

I've just started using the ESP32 WROOM boards and the BLE Bluetooth Sketche samples confuse the hell out of me!

I've been using Arduino boards and the HM-10 BT modules for quite a while now and I'm very adept with them both. Now that I've started using the ESP32 boards I'm so confused with the BLE examples.

I developed an iOS app to view and connect to HM-10 and they're equivalents and send and receive data which works quite well. When a BLE example is loaded and runs, the iOS app can see the ESP32 and connect to it. I just cannot work out how to send and receive data.

All I need is a very basic example which I can use and build on to familiarise myself with the new boards.

Does anyone have such a sketch?

I think a basic one would just include <BLEDevice.h> I assume?

I moved your topic to an appropriate forum category.
In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

You might want to look at this How to get the best out of this forum before you proceed any further.

In your case you posted in the section reserved for the Arduino ESP32. Your first sentence shows you do not have one of those:-

Take a look at this tutorial. Hopefully, it will provide some insight.

Here is a similar tutorial that may explain things more deeply from the coding perspective.

For a project I developed that communicates between a Python client on the PC and an Arduino BLE Server on the ESP32, I use the Nordic UART Service that helps simplify things for me. I use "simplify" loosely since it is as confusing as the rest of BLE. :frowning_face:

Here is an example sketch (using the ESP32 BLE libraries) which will talk back and forth between an ESP32 and phone App.

I find BluefruitConnect a good app for the UART.

 
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
bool newMessage = false;
uint8_t txValue = 0;
bool mR = false;
//std::string rxValue = "";
String rxValue;

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"


class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.println("*********");
        mR = true;
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++)
          Serial.print(rxValue[i]);

        Serial.println();
        newMessage = true;
        Serial.println("*********");
      }
    }
};


void setup() {
  Serial.begin(115200);
  //setup LED
  pinMode(16, OUTPUT); //onboard led LOW to turn on
  digitalWrite(16, HIGH);

  // Create the BLE Device
  BLEDevice::init("UART Service");

  // 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
  pTxCharacteristic = pService->createCharacteristic(
                        CHARACTERISTIC_UUID_TX,
                        BLECharacteristic::PROPERTY_NOTIFY
                      );

  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID_RX,
      BLECharacteristic::PROPERTY_WRITE);

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}
//void respond(std::string  send_message) {
void respond(String  send_message) {
  pTxCharacteristic->setValue(send_message);
  pTxCharacteristic->notify();
}

void loop() {

  if (Serial.available() > 0)
  {
    char monitorInput[50] = "";
    byte len = Serial.readBytesUntil('\n', monitorInput, 49);
    monitorInput[len] = '\0';
    Serial.println("Sending message input from Serial Monitor");
    Serial.println(monitorInput); //echo back to monitor
    Serial.println("*********");
    respond("Received from monitor\n");//shows in phone
    respond(monitorInput);//send on BLE UART
  }

  if (deviceConnected && newMessage) {
    newMessage = false;
    /*
    if (rxValue == String("hello\n").c_str()) {
      digitalWrite(16, LOW);
      delay(1000);
      digitalWrite(16, HIGH);
      respond(String("world\n").c_str());
    }
    */

    respond("Confirm received from phone\n");
    respond(rxValue);
  }

  // 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;
  }
}

Hi cattledog

Thanks for the code..... but I'm getting a load of errors when trying to compile

In file included from /Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE/src/BLECharacteristic.h:20,
                 from /Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE/src/BLEServer.h:23,
                 from /Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:3:
/Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE/src/BLEDescriptor.h:28:7: error: redefinition of 'class BLEDescriptor'
   28 | class BLEDescriptor {
      |       ^~~~~~~~~~~~~
In file included from /Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:25,
                 from /Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLEService.h:23,
                 from /Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLEDevice.h:25,
                 from /Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:2:
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLEDescriptor.h:28:7: note: previous definition of 'class BLEDescriptor'
   28 | class BLEDescriptor {
      |       ^~~~~~~~~~~~~
/Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE/src/BLECharacteristic.h:56:7: error: redefinition of 'class BLECharacteristic'
   56 | class BLECharacteristic {
      |       ^~~~~~~~~~~~~~~~~
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:45:7: note: previous definition of 'class BLECharacteristic'
   45 | class BLECharacteristic  {
      |       ^~~~~~~~~~~~~~~~~
In file included from /Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE/src/BLEServer.h:24:
/Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE/src/BLEService.h:51:7: error: redefinition of 'class BLEService'
   51 | class BLEService {
      |       ^~~~~~~~~~
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLEService.h:28:7: note: previous definition of 'class BLEService'
   28 | class BLEService {
      |       ^~~~~~~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino: In member function 'virtual void MyCallbacks::onWrite(BLECharacteristic*)':
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:34:34: error: 'class BLECharacteristic' has no member named 'getValue'; did you mean 'setValue'?
   34 |       rxValue = pCharacteristic->getValue();
      |                                  ^~~~~~~~
      |                                  setValue
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino: In function 'void setup()':
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:58:14: error: 'init' is not a member of 'BLEDevice'
   58 |   BLEDevice::init("UART Service");
      |              ^~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:61:24: error: 'createServer' is not a member of 'BLEDevice'
   61 |   pServer = BLEDevice::createServer();
      |                        ^~~~~~~~~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:68:33: error: 'class BLEService' has no member named 'createCharacteristic'; did you mean 'addCharacteristic'?
   68 |   pTxCharacteristic = pService->createCharacteristic(
      |                                 ^~~~~~~~~~~~~~~~~~~~
      |                                 addCharacteristic
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:70:44: error: 'PROPERTY_NOTIFY' is not a member of 'BLECharacteristic'
   70 |                         BLECharacteristic::PROPERTY_NOTIFY
      |                                            ^~~~~~~~~~~~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:73:36: error: cannot convert 'BLE2902*' to 'BLEDescriptor&'
   73 |   pTxCharacteristic->addDescriptor(new BLE2902());
      |                                    ^~~~~~~~~~~~~
      |                                    |
      |                                    BLE2902*
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:91:37: note:   initializing argument 1 of 'void BLECharacteristic::addDescriptor(BLEDescriptor&)'
   91 |   void addDescriptor(BLEDescriptor& descriptor);
      |                      ~~~~~~~~~~~~~~~^~~~~~~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:75:53: error: 'class BLEService' has no member named 'createCharacteristic'; did you mean 'addCharacteristic'?
   75 |   BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
      |                                                     ^~~~~~~~~~~~~~~~~~~~
      |                                                     addCharacteristic
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:77:26: error: 'PROPERTY_WRITE' is not a member of 'BLECharacteristic'
   77 |       BLECharacteristic::PROPERTY_WRITE);
      |                          ^~~~~~~~~~~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:79:22: error: 'class BLECharacteristic' has no member named 'setCallbacks'
   79 |   pRxCharacteristic->setCallbacks(new MyCallbacks());
      |                      ^~~~~~~~~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:82:13: error: 'class BLEService' has no member named 'start'
   82 |   pService->start();
      |             ^~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino: In function 'void respond(String)':
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:90:30: error: no matching function for call to 'BLECharacteristic::setValue(String&)'
   90 |   pTxCharacteristic->setValue(send_message);
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:82:7: note: candidate: 'int BLECharacteristic::setValue(const uint8_t*, int)'
   82 |   int setValue(const uint8_t value[], int length) { return writeValue(value, length); }
      |       ^~~~~~~~
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:82:7: note:   candidate expects 2 arguments, 1 provided
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:83:7: note: candidate: 'int BLECharacteristic::setValue(const char*)'
   83 |   int setValue(const char* value) { return writeValue(value); }
      |       ^~~~~~~~
/Users/alexweir/Documents/Arduino/libraries/ArduinoBLE/src/BLECharacteristic.h:83:28: note:   no known conversion for argument 1 from 'String' to 'const char*'
   83 |   int setValue(const char* value) { return writeValue(value); }
      |                ~~~~~~~~~~~~^~~~~
/Users/alexweir/Documents/Arduino/BLE_SendAndReceive_Test/BLE_SendAndReceive_Test.ino:91:22: error: 'class BLECharacteristic' has no member named 'notify'
   91 |   pTxCharacteristic->notify();
      |                      ^~~~~~
Multiple libraries were found for "BLEDevice.h"
  Used: /Users/alexweir/Documents/Arduino/libraries/ArduinoBLE
  Not used: /Users/alexweir/Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/libraries/BLE
exit status 1

Compilation error: 'class BLECharacteristic' has no member named 'getValue'; did you mean 'setValue'?

The compiler is using the ArduinoBLE library instead if the esp32 ble library which is bundled with the esp32 core.

The solution I use, is to edit the properties file of the ArduinoBLE library and remove the esp32 from the allowed architectures.

name=ArduinoBLE
version=1.3.7
author=Arduino
maintainer=Arduino <info@arduino.cc>
sentence=Enables Bluetooth® Low Energy connectivity on the Arduino MKR WiFi 1010, Arduino UNO WiFi Rev.2, Arduino Nano 33 IoT, Arduino Nano 33 BLE, Nicla Sense ME and UNO R4 WiFi.
paragraph=This library supports creating a Bluetooth® Low Energy peripheral & central mode.
category=Communication
url=https://www.arduino.cc/en/Reference/ArduinoBLE
architectures=samd,megaavr,mbed,apollo3,mbed_nano,mbed_portenta,mbed_nicla,mbed_giga,renesas,renesas_portenta,mbed_opta,renesas_uno,silabs
includes=ArduinoBLE.h

An alternative solution is to drag the folder for ArduinoBLE.h from the library folder to your desktop and the compiler will use the esp32 library. You can put it back when you are done compiling.

Hi CattleDog,

Everything works except for sending the Characteristic value from the ESP32 to the phone. At the Xcode end (iOS development tool for creating iOS apps), the characteristic has no value. Here's what I get:-

<CBCharacteristic: 0x282e09740, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = (null), notifying = NO>

I think the value should be created from here I assume?

//void respond(std::string  send_message) {
void respond(String  send_message) {
  pTxCharacteristic->setValue(send_message);
  pTxCharacteristic->notify();
}

What am I doing wrong?

//void respond(std::string  send_message) {
void respond(String  send_message) {
  pTxCharacteristic->setValue(send_message);
  pTxCharacteristic->notify();
}

Correct. respond( ) is the function which sets the value in the characteristic and notifies the phone that a new message is available for it to read. Your issue may be with your phone app and whether it is subscribed for notifications.

The example sketch was written for the BLE message from the Esp32 to the phone to come from Serial input to the ESP32 over usb serial from the monitor.

if (Serial.available() > 0)
  {
    char monitorInput[50] = "";
    byte len = Serial.readBytesUntil('\n', monitorInput, 49);
    monitorInput[len] = '\0';
    Serial.println("Sending message input from Serial Monitor");
    Serial.println(monitorInput); //echo back to monitor
    Serial.println("*********");
    respond("Received from monitor\n");//shows in phone
    respond(monitorInput);//send on BLE UART
  }

OK I think I've caught the correct characteristic. I forcibly sent a string and the phone has caught it:-

<CBCharacteristic: 0x280c58960, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 11, bytes = 0x244675f56720796f752323}, notifying = YES>

The string has 11 characters so I assume this is it. I just need to find out how to get at the bytes value, using Swift, so I can decode it. If you do any iOS development could you let me know how to do this?

What string did you send?

I have no knowledge of Swift and how to decode it to ascii.

I don't live in Appleland and I even had to google "Swift" to know what you were talking about.

All my BLE work has been with Android phone apps, or central apps written for Arduino devices.

You can certainly modify the BLE code to send any bytes you want instead of ascii, but when you began with discussion HM10, I was thinking UART and ascii.

OH WOW FINALLY!!!!! Done it :slight_smile: Thank you so much.

For anyone else who is having the same issue, this little snippet grabs the data out of the characteristic and decodes it.

guard let data = characteristic.value else {
                return
            }
            print(characteristic)
            print(data)
            if var str = String(data: data, encoding: .utf8) {
                print("Successfully decoded: \(str)")
}

Once again CattleDog, thank you so much for your code. I can now create a web server and manipulate the ESP32's I/Os to do what I need....... and now I can do the same with the bluetooth. :slight_smile: thanks to you. I can manipulate and add to your code to start creating my own projects. It's a shame you cannot use both of the solutions in the same board. I did try and it failed because I was using 132% of the 4MB which obviously exceeded its capacity. I'm sure there are ESP32s with more memory out there.

Both wifi and ble use the same radio but I think there are ways to make them share it successfully.
https://esp32.com/viewtopic.php?t=6707

If you issue is the size of the code you might want to try using nimBLE instead of the default bluedroid. It is supposed to use 50% less flash.
https://docs.arduino.cc/libraries/nimble-arduino/

There is a Arduino library with good examples, including one with the nrf UART service and characteristic uuids you are using in the example I provided.

https://github.com/h2zero/NimBLE-Arduino