Page 1 of 1

BLE Multiple characteristics problem

Posted: Fri Apr 09, 2021 3:59 am
by danvica
Hi,
In my application I use three services and one of them contains several characteristics.

The issue is that not all of them are advertised.

I've read that it can happen when you have multiple requests of adding characteristics / descriptors / services and you should wait for onDescriptorWrite event in BluetoothGattCallback to avoid this.

But how exactly ?

I actually use the kolban's libraries and I don't understand how to monitor such events within them.

Here below is my setup code.
BTW: In this case just the first three characteristics are visibile and working. Tested by nRF Android app.


Code: Select all

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

BLECharacteristic* pChar_Flow=NULL;
BLECharacteristic* pChar_SingleShotVolume=NULL;
BLECharacteristic* pChar_DailyConsume=NULL;
BLECharacteristic* pChar_WeekDay=NULL;
BLECharacteristic* pChar_Time=NULL;
BLECharacteristic* pChar_K=NULL;
BLECharacteristic* pChar_Message=NULL;
BLECharacteristic* pChar_DetailedConsume=NULL;
BLECharacteristic* pChar_BatteryLevel=NULL;
BLECharacteristic* pOtaCharacteristic=NULL;

void setup()
{
  BLEDescriptor *pDescriptor;
  BLE2902 *pDescriptor2902;

  esp_log_level_set("*", ESP_LOG_VERBOSE);
  esp_log_set_vprintf(print_F);
  
  Serial.begin(115200);

  if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED))
  {
    Serial.println("SPIFFS Mount Failed");
    return;
  }
  
  setupOTA();
  
  BLEDevice::init("SWater");
  
  BLEDevice::setMTU(BLEMTU);
  
  pServer = BLEDevice::createServer();

  pServer->setCallbacks(new ServerCallbacks());

  
  BLEService *pService = pServer->createService(SERVICE_UUID);
  
  pChar_Flow = pService->createCharacteristic(
                                         CHAR_UUID_FLOWRATE,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                         );

  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("Flow rate");
  
  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);
  
  pChar_Flow->addDescriptor(pDescriptor);
  pChar_Flow->addDescriptor(pDescriptor2902);
  
  pChar_Flow->setCallbacks(new UpdateFlow());
  
  
  pChar_SingleShotVolume = pService->createCharacteristic(
                                         CHAR_UUID_SINGLESHOTVOLUME,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );
  
  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("Single shot volume");
  
  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);
  
  pChar_SingleShotVolume->addDescriptor(pDescriptor);
  pChar_SingleShotVolume->addDescriptor(pDescriptor2902);
  
  pChar_SingleShotVolume->setCallbacks(new UpdateSSV());
  
  
  pChar_DailyConsume = pService->createCharacteristic(
                                         CHAR_UUID_DAILYCONSUME,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );
  
  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("Daily consume");
  
  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);
  
  pChar_DailyConsume->addDescriptor(pDescriptor);
  pChar_DailyConsume->addDescriptor(pDescriptor2902);
  
  pChar_DailyConsume->setCallbacks(new UpdateWC());
  
  pChar_DetailedConsume = pService->createCharacteristic(
                                         CHAR_UUID_DETAILEDCONSUME,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );
                                         
  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("Detailed consume");
  
  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);
  
  pChar_DetailedConsume->addDescriptor(pDescriptor);
  pChar_DetailedConsume->addDescriptor(pDescriptor2902);
  
  pChar_DetailedConsume->setCallbacks(new UpdateDC());
  
  pChar_K = pService->createCharacteristic(CHAR_UUID_KFLOW,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );
  
  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("Generic control");
  
  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);
  
  pChar_K->addDescriptor(pDescriptor);
  pChar_K->addDescriptor(pDescriptor2902);
  
  pChar_K->setCallbacks(new UpdateK());
  
  pChar_K->setValue(KFlowStr);
  
  pChar_Time = pService->createCharacteristic(CHAR_UUID_TIME,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );

  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("DateTime");

  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);

  pChar_Time->addDescriptor(pDescriptor);
  pChar_Time->addDescriptor(pDescriptor2902);
  
  pChar_Time->setCallbacks(new UpdateTime());
  
  
  pChar_Message = pService->createCharacteristic(CHAR_UUID_MESSAGE,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );

  pDescriptor = new BLEDescriptor((uint16_t)0x2901); // Characteristic User Description
  pDescriptor->setValue("Message");

  pDescriptor2902=new BLE2902();
  pDescriptor2902->setNotifications(true);
  
  PacketReadMsg=false;
  pChar_Message->addDescriptor(pDescriptor);
  pChar_Message->addDescriptor(pDescriptor2902);
  
  pChar_Message->setCallbacks(new UpdateMessage());
  
  pChar_Message->setValue("");
  
  pService->start();

  
  BLEService *pServiceBat = pServer->createService(SERVICE_BATTERYUUID);
  
  pChar_BatteryLevel = pServiceBat->createCharacteristic(
                                         CHAR_UUID_BATTERYLEVEL,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );
  
  pChar_BatteryLevel->addDescriptor(new BLE2902());
  
  pChar_BatteryLevel->setCallbacks(new UpdateBatteryLevel());

  pServiceBat->start();
  
  
  BLEService *pServiceOTA = pServer->createService(SERVICE_UUID_OTA);
  
  pOtaCharacteristic = pServiceOTA->createCharacteristic(
                         CHARACTERISTIC_UUID_FW,
                         BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR
                       );

  //pOtaCharacteristic->addDescriptor(new BLE2902());
  pOtaCharacteristic->setCallbacks(new otaCallback());

  pServiceOTA->start();
  

  Serial.println("Create services...done");
  
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->addServiceUUID(SERVICE_BATTERYUUID);
  pAdvertising->addServiceUUID(SERVICE_UUID_OTA);
  
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue (0x06)
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();

Many thanks in advance.

Re: BLE Multiple characteristics problem

Posted: Sun Apr 11, 2021 5:45 am
by danvica
I found the answer by myself.

Kolban's library already takes care of the right events but also defines a maximum number of handles that can be managed.

In BLEServer.h I've increased this value to 30:

Code: Select all

BLEService*     createService(BLEUUID uuid, uint32_t numHandles=30, uint8_t inst_id=0);

Re: BLE Multiple characteristics problem

Posted: Sun Sep 15, 2024 9:10 pm
by buttim
...and you also helped me solve the same problem. Thanks for taking the time to publish the solution after finding it. I think that the default value should not be there so that people could be more aware of an actual limit that could trigger a problem