0

I am using two esp32, one configured as server and the other as client, after establishing the connection, I tried to turn one of them off while keeping the other running and saw that it takes about 6 seconds to detect the disconnection but i want to reduce it to 1 sec or less (as fast as possible).

I tried to connect my phone (client) to the esp server using an app and noticed that when I click disconnect, the server detects the disconnection immediately, how do I achieve the same result with my esp client ?

here's the client code


#include "BLEDevice.h"


//BLE Server name (the other ESP32 name running the server sketch)
#define bleServerName "bc1"
#define connection_LED 21 
/* UUID's of the service, characteristic that we want to read*/
// BLE Service
static BLEUUID ServiceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");

// BLE  state Characteristic
static BLEUUID stateCharacteristicUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");

//Flags stating if should begin connecting and if the connection is up
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;

//Address of the peripheral device. Address will be found during scanning...
static BLEAddress *pServerAddress;
 
//Characteristic that we want to read
static BLERemoteCharacteristic* stateCharacteristic;

//Activate notify
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};

//Flags to check whether new state readings are available
boolean newstate = false;

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
      digitalWrite(connection_LED, HIGH);
  }

  void onDisconnect(BLEClient* pclient) {
    digitalWrite(connection_LED, LOW);
    connected = false;
  }
};

//Connect to the BLE Server that has the name, Service, and Characteristics
   bool connectToServer(BLEAddress pAddress) {
   BLEClient* pClient = BLEDevice::createClient();
   pClient->setClientCallbacks(new MyClientCallback());
   
  // Connect to the remote BLE Server.
  pClient->connect(pAddress);
  Serial.println(" - Connected to server");
 
  // Obtain a reference to the service we are after in the remote BLE server.
  BLERemoteService* pRemoteService = pClient->getService(ServiceUUID);
  if (pRemoteService == nullptr) {
    Serial.print("Failed to find our service UUID: ");
    Serial.println(ServiceUUID.toString().c_str());
    pClient->disconnect();
    return (false);
  }
  Serial.println(" - Found our service");
  
  // Obtain a reference to the characteristics in the service of the remote BLE server.
  stateCharacteristic = pRemoteService->getCharacteristic(stateCharacteristicUUID);
  if (stateCharacteristic == nullptr) {
    Serial.print("Failed to find our characteristic UUID");
    Serial.println(charUUID.toString().c_str());
    pClient->disconnect();
    return false;
  }
  Serial.println(" - Found our characteristics");
 
  //Assign callback functions for the Characteristics
  stateCharacteristic->registerForNotify(stateNotifyCallback);
  return true;
}

//Callback function that gets called, when another device's advertisement has been received
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    if (advertisedDevice.getName() == bleServerName) { //Check if the name of the advertiser matches
      advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
      pServerAddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
      doConnect = true; //Set indicator, stating that we are ready to connect
      doScan = true;
      Serial.println("Device found. Connecting!");
    }
  }
};
 
//When the BLE Server sends a new state reading with the notify property
static void stateNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, 
                                    uint8_t* pData, size_t length, bool isNotify) {
  newstate = true;
}

void setup() {

  pinMode(connection_LED, OUTPUT);
  //Start serial communication
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  Serial.println("waiting for a server connection...");
  
  //Init BLE device
  BLEDevice::init("");
 
  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 30 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(30);
  
}

void loop() {
  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer(*pServerAddress)) {
      Serial.println("We are now connected to the BLE Server.");
      
      //Activate the Notify property of each Characteristic
      stateCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
      connected = true;
    } else {
      Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");     
    }
    doConnect = false;
  }

  if(connected){
 //if new state readings are available, 
  if (newstate){
    newstate = false;
    std::string value = stateCharacteristic->readValue();
    Serial.println(value);
  } 
 } else if(doScan){
    
    Serial.println("Disconnected from server");
    Serial.println("rescan");
    BLEDevice::getScan()->start(0);  //  starting scan after disconnect
  }
}
Vass
  • 1
  • 2
  • You just set the desired "supervision timeout" in the connection parameters. This is an important part of the BLE standard. – Emil May 21 '22 at 23:46
  • Thank you for answering, I’m using the esp32 ble server example on arduino ide, how do I add supervision timeout to the code ? – Vass May 22 '22 at 10:31
  • Please provide enough code so others can better understand or reproduce the problem. – Community May 23 '22 at 13:47
  • @Emil Thank you for answering, I’m using the esp32 ble server example on arduino ide, how do I add supervision timeout to the code ? – Vass May 24 '22 at 01:24

1 Answers1

0

You could access the actual GATT event flow that ends in invoking the BLEServer::onDisconnect method.

There are events for both GATT clients and servers. These are enumerated in esp_gattc_api.h and esp_gatts_api.h

For example, you can set a custom GATT handler before initialization. The handler is called immediately after a GATT event is processed (hook pattern).

static void my_gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) {
    // Do stuff depending on event type
    // Eg. 'listen' to GATT events in realtime (very star trek).
    // tone(2000 + event*200, volume, delay);
}

in your setup()

BLEDevice::setCustomGattsHandler(my_gatts_event_handler);
BLEDevice::init(SERVICE_NAME);

You will see (hear) that GATT events are sent before BLEServer::onDisconnect() is called. You can do stuff earlier in the disconnect flow, but remember that BLEServer depends on this flow to call onDisconnect();

Dominic Cerisano
  • 3,522
  • 1
  • 31
  • 44