ESP32 BLE Exception when trying to connect to Characteristics

Hi,
I'm working on a personal project to connect to a bluetooth device and control it from an ESP32.
Using a bluetooth app on my phone, I can connect to this device, access the service + characteristic, and write a value e.g. to change the color (similar to this project: https://bitbucket.org/stuartpatterson/esp32_ble_lumin_random_rgb/src/master/esp32_ble_lumin_random_rgb.ino )

I wrote the following program to scan for devices and connect based on the name. I also tested it using callbacks but I currently do it in the setup.

#include "BLEDevice.h"
static BLEUUID serviceUUID("390d9772-3889-11ec-8d3d-0242ac130003");
static BLEUUID charUUID("318c0fa6-3889-11ec-8d3d-0242ac130003");
bool connected = false;

BLEClient* pMyClient = BLEDevice::createClient();
BLERemoteService* pMyRemoteService;
BLERemoteCharacteristic* pMyRemoteCharacteristic;
static BLEAdvertisedDevice* pMyDevice;

static String robotName = "MyRobot";
uint8_t rgb_color_data[] = { 0x00, 0xFF, 0xFF, 0x21, 0x20, 0xFF };

void setup() {
  Serial.begin(115200);
  while(!Serial){};
  Serial.println("Starting Controller application...");
  BLEDevice::init("Controller");
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
  pBLEScan->setActiveScan(true);
  BLEScanResults pfoundDevices = pBLEScan->start(5, false);
  int count = pfoundDevices.getCount();
    Serial.print("Found "); Serial.print(count); Serial.println(" devices");
    for (int i = 0; i < count; i++) {
      BLEAdvertisedDevice bluetoothDevice = pfoundDevices.getDevice(i); 
      Serial.print("[INFO] Checking device "); Serial.println(bluetoothDevice.getName().c_str());
      String deviceName = bluetoothDevice.getName().c_str();
       if (deviceName == robotName) {
         Serial.println(bluetoothDevice.toString().c_str());
          BLEDevice::getScan()->stop();
          Serial.print("Connecting with "); Serial.println(deviceName);
          pMyDevice = new BLEAdvertisedDevice(bluetoothDevice); 
           if (pMyClient->connect(pMyDevice)) {
            Serial.println("[OK] device connected");
            Serial.print("[INFO] Connecting to service ");   Serial.println(serviceUUID.toString().c_str());
            pMyRemoteService = pMyClient->getService(serviceUUID);
            Serial.println("[OK] service connected");
            Serial.print("[INFO] Connecting to characteristic ");   Serial.println(charUUID.toString().c_str());
            pMyRemoteCharacteristic = pMyRemoteService->getCharacteristic(charUUID);
            Serial.println("[OK] characteristic connected");
            connected = true;
           }
       }
    } 
}

void loop() {
  if ( connected ) {
    Serial.println("[OK] Updating value");
    if ( pMyRemoteCharacteristic != NULL ) {
      if ( pMyRemoteCharacteristic->canWriteNoResponse() ) {
        r = random(0,256);
        g = random(0,256);
        b = random(0,256);        
        rgb_color_data[4] = r;
        rgb_color_data[5] = g;
        rgb_color_data[3] = b;
        Serial.println("[INFO] Writing value...");
        pMyRemoteCharacteristic->writeValue(rgb_color_data, sizeof(rgb_color_data));        
        Serial.println("[OK] Done");
        delay(500);
      }
    }
  }
}

Below is the log from the Serial Monitor. First it takes 1 minute to connect to the service. Then accessing the characteristic leads to the Exception error.

I welcome any comment on anything I might be doing wrong.
Thanks

09:14:52.210 -> Starting Controller application...
09:14:57.201 -> Found 5 devices
09:14:57.201 -> [INFO] Checking device 
09:14:57.201 -> [INFO] Checking device 
09:14:57.201 -> [INFO] Checking device 
09:14:57.201 -> [INFO] Checking device 
09:14:57.201 -> [INFO] Checking device MyRobot
09:14:57.201 -> Name: MyRobot
09:14:57.235 -> Connecting with MyRobot
09:15:37.527 -> [OK] device connected
09:15:37.527 -> [INFO] Connecting to service UUID
09:16:37.507 -> [OK] service connected
09:16:37.507 -> [INFO] Connecting to characteristic UUID
09:16:37.542 -> Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
09:16:37.542 -> Core 1 register dump:
09:16:37.542 -> PC      : 0x400d4fce  PS      : 0x00060330  A0      : 0x800d19cd  A1      : 0x3ffc7350  
09:16:37.542 -> A2      : 0x00000000  A3      : 0x62679b60  A4      : 0x3ffc427c  A5      : 0x4548a885  
09:16:37.542 -> A6      : 0x136c5f13  A7      : 0x00018903  A8      : 0x80177ccd  A9      : 0x3ffc7370  
09:16:37.542 -> A10     : 0x3ffdcff8  A11     : 0x3ffdcff8  A12     : 0x3ffc737c  A13     : 0x00000000  
09:16:37.576 -> A14     : 0x00000003  A15     : 0x00000013  SAR     : 0x00000008  EXCCAUSE: 0x0000001c  
09:16:37.576 -> EXCVADDR: 0x00000034  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  
09:16:37.576 -> 
09:16:37.576 -> ELF file SHA256: 0000000000000000
09:16:37.576 -> 
09:16:37.576 -> Backtrace: 0x400d4fce:0x3ffc7350 0x400d19ca:0x3ffc73b0 0x400d7da6:0x3ffc7520 0x4008ff66:0x3ffc7540
09:16:37.576 -> 
09:16:37.576 -> Rebooting...

Note that I also tried connecting to the service and char with
pMyRemoteService = pMyClient->getService(BLEUUID(serviceUUID));

After you have looked up ESP Exception Decoder, have installed it and pasted your exception into the decoder and the decoder prints out its results, could you post those results here?

Here is a suggestion for your code:

1 Like

Thank you for your replies.
After some further investigations, I started over with the BLE Beacon Scanner example.
This appears to be an issue with the device I'm trying to use i.e. my ESP32 doesn't see any service.
advertisedDevice.haveServiceUUID() returns 0 and advertisedDevice.getServiceUUID() is null

Looking at my device on an iPhone app (LightBlue), it sees the robot device and it mentions "No services" below (or BlueCap app says Services :0)
When I connect to it, I can see and browse into 5 services, including the one I want to use. Opening this service, I have access to the 2 characteristics I want to use.

So I tried adding the following in the MyAdvertisedDeviceCallbacks

 Serial.print("Device name: ");
Serial.println(advertisedDevice.getName().c_str());
   BLEClient* pMyClient = BLEDevice::createClient(); 
        pMyClient->connect(advertisedDevice.getAddress());        
      Serial.print("Nb of services  "); Serial.println(String(pMyClient->getServices()->size()));

Nb of services is never displayed so I'm not sure what I'm doing wrong.
I'd like after to find a way to loop on pMyClient->getServices(); but not unsure how to do this.
Am I looking at the right info to attempt finding the service I need?

Thanks

Again, you should check for null pointer:

BLEClient* pMyClient = BLEDevice::createClient();
if (pMyClient == NULL) Serial.println("Unable to create client");
else
{
  Serial.println("Client created, connecting...");
  //Convert coffee to more code here..
}

Could some sort of failed pairing be the problem?

Sir I have problem with the code . The code working well for esp32 and hc05 Bluetooth module but when I use it with esp 32 internal Bluetooth classic it is not working fine . Which library will be use for for this purpose . My project is read and write data over serial UART port and I am converting this project from Arduino to ESP 32 .
// this for reading/writing to eeprom 24LC256 chip
#include <Wire.h>
#define disk1 0x50 //Address of 24LC256 eeprom chip

long tmr;
long tmrStart;
long tmrNow;
int serialState=0;

String incomingMessage;
String msgToParse;
bool msgWaiting=false;
unsigned int eepromAddress;

// just some temporary variables
int i;
int j;
int k;
int h;

void writeEEPROM(unsigned int eeaddress, byte data) {
Wire.beginTransmission(disk1);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(data);
Wire.endTransmission();
delay(5); // writing can take up to 5m/s per address
}

byte readEEPROM(unsigned int eeaddress) {
byte rdata = 0xFF;
Wire.beginTransmission(disk1);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(disk1, 1);
if (Wire.available()){ rdata = Wire.read();}
return rdata;
}

void resetTimer(){
tmrStart=millis();
tmr=0;
}

long getTime(){
long t=millis();
t=t-tmrStart;
return t;
}

void getSerialData(){
if(Serial.available() == true){
while(Serial.available() == true && msgWaiting==false){
byte b=Serial.read();
if(b==0x0a){
// this is an end of string/message terminating character
// so update the message to parse and set a flag
msgToParse = incomingMessage;
incomingMessage = "";
msgWaiting = true;

     }else if(b==0x0d){
        // ignore linefeed characters
     }else{
        // keep adding incoming characters to the receive string
        incomingMessage = incomingMessage + char(b);
     }         
  }      

}
}

int getValueFrom(int k){
// assumes a two-character value from the message string
// starting at position k - so a string like AFE0596 might
// be from 1 = 0xFE, from 3 = 0x05, from 5 = 0x96
int b1 = int(msgToParse.charAt(k));
int b2 = int(msgToParse.charAt((k+1)));

if(b1 >= 48 && b1 <= 57){ b1 = b1 - 48;}
if(b1 >= 65 && b1 <= 74){ b1 = b1 - 55;}
if(b2 >= 48 && b2 <= 57){ b2 = b2 - 48;}
if(b2 >= 65 && b2 <= 74){ b2 = b2 - 55;}

int j = b1 * 16;
j = j + b2;
return(j);
}

void parseMessage(){
int deviceID = getValueFrom(0);
int commandByte = getValueFrom(2);
int commandValue = getValueFrom(4);

Serial.print(F("device:"));
Serial.print(deviceID);
Serial.print(F(" command:"));
Serial.print(commandByte);
Serial.println(" ");

Serial.print(F(" value:"));
Serial.print(commandValue);

switch(commandByte){

  case 'W':
  // write data to the specified eeprom address
  // (address should be two bytes)
  
  eepromAddress = commandValue * 256;
  commandValue = getValueFrom(6);
  eepromAddress += commandValue;

  Serial.print(F("writing to eeprom address: "));
  Serial.println(eepromAddress);

  // now go through the string until there are no more characters left
  // and "stream write" them to the eeprom chip
  k = 8;
  j = msgToParse.length();
  Serial.print(j);
  Serial.println(" characters in string");
  
  h = 0;
  while(k < j){
     commandValue = getValueFrom(k);

     Serial.print("pos:");
     Serial.print(k);
     Serial.print(" value:");
     Serial.println(commandValue);
     
     writeEEPROM(eepromAddress, byte(commandValue));

eepromAddress++;
h++;
k += 2;
}

  Serial.print(h);
  Serial.println(F(" bytes written"));
  break;

  case 'Q':
  // testing: read back data from eeprom address
  eepromAddress = commandValue * 256;
  commandValue = getValueFrom(6);
  eepromAddress += commandValue;

  commandValue = getValueFrom(8);

  Serial.print(F("reading "));
  Serial.print(commandValue);
  Serial.print(F(" bytes from eeprom address: "));
  Serial.println(eepromAddress);

  for(h=0; h < commandValue; h++){
     byte b = readEEPROM(eepromAddress);
     Serial.print(F("value: "));
     Serial.println(b);
     eepromAddress++;
  }

}
}

void setup() {
// put your setup code here, to run once:
Serial.begin(57600);
Wire.begin();
}

void loop() {
// put your main code here, to run repeatedly:

getSerialData();
if(msgWaiting==true){
Serial.print(F("received: "));
Serial.println(msgToParse);
parseMessage();
msgWaiting=false;
}

}

I tried your suggestion and the client is created ok.
The issue is when I connect to the device ; nothing happens (the message Client connected... is never displayed). I tried with and without connecting with the address type (1).

 BLEClient* pMyClient = BLEDevice::createClient(); 
        if (pMyClient == NULL) Serial.println("Unable to create client");
        else
        {
            esp_ble_addr_type_t type = advertisedDevice.getAddressType(); 
            Serial.println("Server address type: " + String(type));
            delay(100);
            Serial.print("Client created, connecting...");
            pMyClient->connect(advertisedDevice.getAddress(), type); 
            Serial.println("Client connected...");
            Serial.print("Nb of services  "); Serial.println(String(pMyClient->getServices()->size()));
        }

Try this instead:

BLEAddress *addr = new BLEAddress(advertisedDevice.getAddress());
pMyClient->connect(addr);

Unfortunately there's an error when doing the verify:

no matching function for call to 'BLEClient::connect(BLEAddress*&)'