ESP32 BLE does not disconnect

I use ESP32 BLE to connect with bluetooth devices. The problem is that when I exit the app it doesn't disconnect and when I try to search for the Blueetooh device again, it doesn't appear.

My code is the following:

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

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
const int LED = 2; // Could be different depending on the dev board. I used the DOIT ESP32 dev board.

//std::string rxValue; // Could also make this a global var to access it in loop()

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#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) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");

        for (int i = 0; i < rxValue.length(); i++) {
          Serial.print(rxValue[i]);
        }

        Serial.println();

        // Do stuff based on the command received from the app
        if (rxValue.find("1") != -1) { 
          Serial.println("Turning ON!");
          digitalWrite(LED, HIGH);
        }
        else if (rxValue.find("0") != -1) {
          Serial.println("Turning OFF!");
          digitalWrite(LED, LOW);
        }

        Serial.println();
        Serial.println("*********");
      }
    }
};

void setup() {
  Serial.begin(115200);

  pinMode(LED, OUTPUT);

  // Create the BLE Device
  BLEDevice::init("ESP32"); // Give it a name

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
                      
  pCharacteristic->addDescriptor(new BLE2902());

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

  pCharacteristic->setCallbacks(new MyCallbacks());

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

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  if (deviceConnected) {

    String dataExample1 = "DATA1";
    String dataExample2 = "DATA2";
    txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!
    
    //convert float txvalue to string
    char txString[8]; // make sure this is big enuffz
    dtostrf(txValue, 1, 2, txString);
    

    String str = "";
    str += txString;
    str += ",";
    str += dataExample1;
    str += ",";
    str += dataExample2;
    
    
    pCharacteristic->setValue((char*)str.c_str());
    pCharacteristic->notify(); // Send the value to the app!
    
    Serial.print("*** Sent Value: ");
    Serial.print(str);
    Serial.println(" ***");

  }
  delay(1000);
}

I'm new to this technology and I don't know if there is a way that if it detects that it's not connected to anything it will reboot or something, I don't know.

But, what I do want is for it to stay connected even if I have the screen closed (it works like this right now). My only problem is that when I close the app and reopen it, the device no longer appears.

I use the bluettoh terminal app with Android. Although it works the same with any other:

I'm not exactly certain of what you are asking, but try this modified version of your code to see if it reconnects as you want.

BLEServer declaration is now global similar to you did with BLECharacteristic. I have added a function checkToReconnect() which manages the reconnection in loop.

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

BLEServer *pServer = NULL;//added
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;//added
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
const int LED = 2; // Could be different depending on the dev board. I used the DOIT ESP32 dev board.

//std::string rxValue; // Could also make this a global var to access it in loop()

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#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) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");

        for (int i = 0; i < rxValue.length(); i++) {
          Serial.print(rxValue[i]);
        }

        Serial.println();

        // Do stuff based on the command received from the app
        if (rxValue.find("1") != -1) { 
          Serial.println("Turning ON!");
          digitalWrite(LED, HIGH);
        }
        else if (rxValue.find("0") != -1) {
          Serial.println("Turning OFF!");
          digitalWrite(LED, LOW);
        }

        Serial.println();
        Serial.println("*********");
      }
    }
};

void checkToReconnect() //added
{
  // disconnected so advertise
  if (!deviceConnected && oldDeviceConnected) {
    delay(500); // give the bluetooth stack the chance to get things ready
    pServer->startAdvertising(); // restart advertising
    Serial.println("Disconnected: start advertising");
    oldDeviceConnected = deviceConnected;
  }
  // connected so reset boolean control
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    Serial.println("Reconnected");
    oldDeviceConnected = deviceConnected;
  }
}

void setup() {
  Serial.begin(115200);

  pinMode(LED, OUTPUT);

  // Create the BLE Device
  BLEDevice::init("ESP32"); // Give it a name

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
                      
  pCharacteristic->addDescriptor(new BLE2902());

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

  pCharacteristic->setCallbacks(new MyCallbacks());

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

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  
  checkToReconnect();
  
  if (deviceConnected) {

    String dataExample1 = "DATA1";
    String dataExample2 = "DATA2";
    txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!
    
    //convert float txvalue to string
    char txString[8]; // make sure this is big enuffz
    dtostrf(txValue, 1, 2, txString);
    

    String str = "";
    str += txString;
    str += ",";
    str += dataExample1;
    str += ",";
    str += dataExample2;
    
    
    pCharacteristic->setValue((char*)str.c_str());
    pCharacteristic->notify(); // Send the value to the app!
    
    Serial.print("*** Sent Value: ");
    Serial.print(str);
    Serial.println(" ***");

  }
  
  delay(1000);
}
1 Like

Thank you very much, you are the best. It works perfectly!

Thanks for the kind words and I'm glad the code does what you want.

I'm new to this technology and I don't know if there is a way that if it detects that it's not connected to anything it will reboot or something, I don't know.

The important thing to realize, is that when a peripheral device is connected it stops advertising. A central device, like a phone, can only find and connect to an advertising peripheral.

If you want the central to reconnect without the peripheral going through a reset and repeat of setup(), then the peripheral needs to start advertising somewhere else than in setup().

Because advertising starts with this pServer function
pServer->startAdvertising();

it means that you need global scope for the initial declaration for pServer
BLEServer *pServer

1 Like

I don't know if you can help me, but I will still ask the question:

I am trying to notify and read the data from my app in Flutter. Sending data to ESP32 with the buttons to turn it on and off is fine, my problem is with reading the data that the Arduino sends.

I will share the code snippets below:

Arduino:

void loop() {
  
  checkToReconnect();
  
  if (deviceConnected) {

    float dataExample1 = 0.4;
    float dataExample2 = 0.5;
    txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!
    
    //convert float txvalue to string
    char txString[8]; // make sure this is big enuffz
    dtostrf(txValue, 1, 2, txString);
    

    String str = "";
    str += txString;
    str += ",";
    str += dataExample1;
    str += ",";
    str += dataExample2;
    
    
    pCharacteristic->setValue((char*)str.c_str());
    pCharacteristic->notify(); // Send the value to the app!
    
    Serial.print("*** Sent Value: ");
    Serial.print(str);
    Serial.println(" ***");

  }
  
  delay(1000);
}

Flutter:

Container(
                  child: StreamBuilder<List<int>>(
                    stream: stream,
                    builder: (BuildContext context,
                        AsyncSnapshot<List<int>> snapshot) {
                      if (snapshot.hasError)
                        return Text('Error: ${snapshot.error}');

                      if (snapshot.connectionState == ConnectionState.active) {
                        var data = snapshot.data as List<int>;
                        var currentValue = _dataParser(data);
                        print("REAL_DATA_1: $data");
                       // _temphumidata = currentValue.split(",");
                        //_charge = double.parse('${_temphumidata[0]}');
                        //_data_1 = double.parse('${_temphumidata[1]}');

print("REAL_DATA_1: $data");
It appears blank. You should have the information sent... but it doesn't happen like that. A friend tell me that it is a problem with my Arduino code.

I know nothing about Flutter.

The previous code posted in reply #2 worked with the Kai Morich Bluetooth Serial Terminal as the receiver. I replaced the if(device connected) section with your new snippet and all is received correctly.

There is no new line in the sending, so the format is a little confusing, but all the data is correct and separated by a terminal timestamp.

A friend tell me that it is a problem with my Arduino code.

I'd be happy to work with you change the Arduino code to work with Flutter, instead of the Serial Bluetooth Terminal app, but your friend will have to tell us what to do.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.