nkolban / esp32-snippets

Sample ESP32 snippets and code fragments
https://leanpub.com/kolban-ESP32
Apache License 2.0
2.37k stars 710 forks source link

BLEClient -> getServices() doesn't work #1098

Open GF65gh opened 3 years ago

GF65gh commented 3 years ago

Hi, I'm working on a personal project to connect to a bluetooth enabled robot device and control it from an ESP32. Using a bluetooth app on my phone, I can connect to this device, access the service + characteristic I need, and write a value e.g. to change the color.

I'm working on a program based on the BLE Beacon Scanner example. I'm trying to connect to the service and characteric based on their UUID. The first issue I got is that the 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 assume the solution involves using BLEClient::getServices yet running the program (see below) go until message "Client created, connecting..."

Is there a solution to loop on BLERemoteService items returned by getServices to use the appropriate service.

static BLEAdvertisedDevice* myDevice;
int scanTime = 5; //In seconds
BLEScan *pBLEScan;

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
    void onResult(BLEAdvertisedDevice advertisedDevice)
    {
      if (advertisedDevice.haveName())
      {
        Serial.print("Device name: ");
        Serial.println(advertisedDevice.getName().c_str());        
        Serial.print("Address : ");        
        Serial.println(advertisedDevice.getAddress().toString().c_str());
        Serial.print("haveServiceUUID: "); Serial.println(advertisedDevice.haveServiceUUID());
        Serial.print("device's UUID: "); Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
        //Connecting to client      
        BLEClient* pMyClient = BLEDevice::createClient(); 
        if (pMyClient == NULL) Serial.println("Unable to create client");
        else
        {
            Serial.print("Client created, connecting...");
            esp_ble_addr_type_t type = advertisedDevice.getAddressType(); 
            Serial.println("Server address type: " + String(type));
            delay(100);
            pMyClient->connect(advertisedDevice.getAddress(), type); 
            Serial.println("Client connected...");
            Serial.print("Nb of services  "); Serial.println(String(pMyClient->getServices()->size()));
            std::map<std::string, BLERemoteService*> *pRemoteServices = pMyClient->getServices();
            Serial.println("Getting services...");
        }     
      }
   }
};

void setup()
{
  Serial.begin(115200);
  Serial.println("Scanning...");
  BLEDevice::init("Controller");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99); // less or equal setInterval value
}

void loop()
{
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
  pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
  delay(2000);
}
chegewara commented 3 years ago

Yes, it does not work the way you are doing it. Code is based on events and you cant perform some operations from withing an event. Follow examples.

GF65gh commented 3 years ago

Thank you, I used the BLE Client Test and getServices() works but I'm getting a size of 0. With the BlueCap app I use, I can see that my device has 5 UUIDs yet could these be not exposed as services and require a different access ?


`bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");
    pClient->setClientCallbacks(new MyClientCallback());
    // Connect to the remove BLE Server.
    pClient->connect(myDevice);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");

      //OK
      //Get Services
      std::map<std::string, BLERemoteService*> *pRemoteServices = pClient->getServices();
      Serial.print("Nb of services: "); Serial.println(pRemoteServices->size());`
chegewara commented 3 years ago

Maybe it is case similar to other one recently was reported. Solution was to add small delay between connect and get services.