Connection problems when using BLE and WiFi with ESP32

Hi together,

I wanted to use a Lolin32 board as some kind of hub for multiple Xiaomi Mi Flora plant sensors. Currently I’m using a single sensor for testing if the whole concept is feasible. The code I used for this is based on sidddy’s implementation (https://github.com/sidddy/flora). The whole MQTT stuff got replaced by the Blynk API and everything is working fine … to a certain point, at least.
The sensor is being read every 15 minutes at the moment, but after some time, usually a few hours, the sensor values will still be read, but a connection to Blynk can not be established anymore.
Has anyone an idea what the cause could be? Or how I can find it out?

Here is my code:


#include "BLEDevice.h"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>

#define BLYNK_NO_BUILTIN   // Disable built-in analog & digital pin operations

// array of different xiaomi flora MAC addresses
char* FLORA_DEVICES[] = {
    "c4:7c:xx:xx:xx:xx", 
};

// sleep between to runs in seconds
#define SLEEP_DURATION 15 * 60
// emergency hibernate countdown in seconds
#define EMERGENCY_HIBERNATE 3 * 60
// how often should the battery be read - in run count
#define BATTERY_INTERVAL 1
// how often should a device be retried in a run when something fails
#define RETRY 5

const char*   WIFI_SSID       = "xxx";
const char*   WIFI_PASSWORD   = "xxx";

const char    auth[] = "xxx";

// boot count used to check if battery status should be read
RTC_DATA_ATTR int bootCount = 0;

// device count
static int deviceCount = sizeof FLORA_DEVICES / sizeof FLORA_DEVICES[0];

// the remote service we wish to connect to
static BLEUUID serviceUUID("00001204-0000-1000-8000-00805f9b34fb");

// the characteristic of the remote service we are interested in
static BLEUUID uuid_version_battery("00001a02-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_sensor_data("00001a01-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_write_mode("00001a00-0000-1000-8000-00805f9b34fb");

TaskHandle_t hibernateTaskHandle = NULL;

WiFiClient espClient;

float temperature;
int moisture;
int light;
int conductivity;
int battery;
std::string sw_version;

void connectWifi() {
  Serial.println("Connecting to WiFi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("");
}

void disconnectWifi() {
  WiFi.disconnect(true);
  Serial.println("WiFi disonnected");
}

BLEClient* getFloraClient(BLEAddress floraAddress) {
  BLEClient* floraClient = BLEDevice::createClient();

  if (!floraClient->connect(floraAddress)) {
    Serial.println("- Connection failed, skipping");
    return nullptr;
  }

  Serial.println("- Connection successful");
  return floraClient;
}

BLERemoteService* getFloraService(BLEClient* floraClient) {
  BLERemoteService* floraService = nullptr;

  try {
    floraService = floraClient->getService(serviceUUID);
  }
  catch (...) {
    // something went wrong
  }
  if (floraService == nullptr) {
    Serial.println("- Failed to find data service");
  }
  else {
    Serial.println("- Found data service");
  }

  return floraService;
}

bool forceFloraServiceDataMode(BLERemoteService* floraService) {
  BLERemoteCharacteristic* floraCharacteristic;
  
  // get device mode characteristic, needs to be changed to read data
  Serial.println("- Force device in data mode");
  floraCharacteristic = nullptr;
  try {
    floraCharacteristic = floraService->getCharacteristic(uuid_write_mode);
  }
  catch (...) {
    // something went wrong
  }
  if (floraCharacteristic == nullptr) {
    Serial.println("-- Failed, skipping device");
    return false;
  }

  // write the magic data
  uint8_t buf[2] = {0xA0, 0x1F};
  floraCharacteristic->writeValue(buf, 2, true);

  delay(500);
  return true;
}

bool readFloraDataCharacteristic(BLERemoteService* floraService) {
  BLERemoteCharacteristic* floraCharacteristic = nullptr;

  // get the main device data characteristic
  Serial.println("- Access characteristic from device");
  try {
    floraCharacteristic = floraService->getCharacteristic(uuid_sensor_data);
  }
  catch (...) {
    // something went wrong
  }
  if (floraCharacteristic == nullptr) {
    Serial.println("-- Failed, skipping device");
    return false;
  }

  // read characteristic value
  Serial.println("- Read value from characteristic");
  std::string value;
  try{
    value = floraCharacteristic->readValue();
  }
  catch (...) {
    // something went wrong
    Serial.println("-- Failed, skipping device");
    return false;
  }
  const char *val = value.c_str();

  Serial.print("Hex: ");
  for (int i = 0; i < 16; i++) {
    Serial.print((int)val[i], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  int16_t* temp_raw = (int16_t*)val;
  temperature = (*temp_raw) / ((float)10.0);
  Serial.print("-- Temperature: ");
  Serial.println(temperature);

  moisture = val[7];
  Serial.print("-- Moisture: ");
  Serial.println(moisture);

  light = val[3] + val[4] * 256;
  Serial.print("-- Light: ");
  Serial.println(light);
 
  conductivity = val[8] + val[9] * 256;
  Serial.print("-- Conductivity: ");
  Serial.println(conductivity);

  if (temperature > 200) {
    Serial.println("-- Unreasonable values received, skip publish");
    return false;
  }
  return true;
}

bool readFloraBatteryCharacteristic(BLERemoteService* floraService) {
  BLERemoteCharacteristic* floraCharacteristic = nullptr;

  // get the device battery characteristic
  Serial.println("- Access battery characteristic from device");
  try {
    floraCharacteristic = floraService->getCharacteristic(uuid_version_battery);
  }
  catch (...) {
    // something went wrong
  }
  if (floraCharacteristic == nullptr) {
    Serial.println("-- Failed, skipping battery level");
    return false;
  }

  // read characteristic value
  Serial.println("- Read value from characteristic");
  std::string value;
  try{
    value = floraCharacteristic->readValue();
  }
  catch (...) {
    // something went wrong
    Serial.println("-- Failed, skipping battery level");
    return false;
  }
  const char *val2 = value.c_str();
  battery = val2[0];
  sw_version = value.substr (2,5); 

  Serial.print("-- Battery: ");
  Serial.println(battery);

  Serial.print("-- Firmware Version: ");
  Serial.println(sw_version.c_str());

  return true;
}

bool processFloraService(BLERemoteService* floraService, char* deviceMacAddress, bool readBattery) {
  // set device in data mode
  if (!forceFloraServiceDataMode(floraService)) {
    return false;
  }

  bool dataSuccess = readFloraDataCharacteristic(floraService);

  bool batterySuccess = true;
  if (readBattery) {
    batterySuccess = readFloraBatteryCharacteristic(floraService);
  }

  return dataSuccess && batterySuccess;
}

bool processFloraDevice(BLEAddress floraAddress, char* deviceMacAddress, bool getBattery, int tryCount) {
  Serial.print("Processing Flora device at ");
  Serial.print(floraAddress.toString().c_str());
  Serial.print(" (try ");
  Serial.print(tryCount);
  Serial.println(")");

  // connect to flora ble server
  BLEClient* floraClient = getFloraClient(floraAddress);
  if (floraClient == nullptr) {
    return false;
  }

  // connect data service
  BLERemoteService* floraService = getFloraService(floraClient);
  if (floraService == nullptr) {
    floraClient->disconnect();
    return false;
  }

  // process devices data
  bool success = processFloraService(floraService, deviceMacAddress, getBattery);

  // disconnect from device
  floraClient->disconnect();

  return success;
}

void hibernate() {
  esp_sleep_enable_timer_wakeup(SLEEP_DURATION * 1000000ll);
  Serial.println("Going to sleep now.");
  delay(100);
  esp_deep_sleep_start();
}

void delayedHibernate(void *parameter) {
  delay(EMERGENCY_HIBERNATE*1000); // delay for five minutes
  Serial.println("Something got stuck, entering emergency hibernate...");
  hibernate();
}

void setup() {
  // all action is done when device is woken up
  Serial.begin(115200);
  delay(1000);

  // increase boot count
  bootCount++;

  // create a hibernate task in case something gets stuck
  xTaskCreate(delayedHibernate, "hibernate", 4096, NULL, 1, &hibernateTaskHandle);

  Serial.println("Initialize BLE client...");
  BLEDevice::init("");
  BLEDevice::setPower(ESP_PWR_LVL_P7);

  // connecting wifi 
  //connectWifi();

  // check if battery status should be read - based on boot count
  bool readBattery = ((bootCount % BATTERY_INTERVAL) == 0);

  // process devices
  for (int i=0; i<deviceCount; i++) {
    int tryCount = 0;
    char* deviceMacAddress = FLORA_DEVICES[i];
    BLEAddress floraAddress(deviceMacAddress);

    while (tryCount < RETRY) {
      tryCount++;
      if (processFloraDevice(floraAddress, deviceMacAddress, readBattery, tryCount)) {
        break;
      }
      delay(1000);
    }
    delay(1500);
  }

  Blynk.begin(auth, WIFI_SSID, WIFI_PASSWORD);
  if(Blynk.connect())
  {
    Serial.println("Blynk connected.");
  } 
  else
  {
    Serial.println("Blynk connection failed");
  }
  Blynk.virtualWrite(V1, battery);
  //Blynk.virtualWrite(V2, sw_version.c_str());
  Blynk.virtualWrite(V6, temperature);
  Blynk.virtualWrite(V7, moisture);
  Blynk.virtualWrite(V8, light);
  Blynk.virtualWrite(V9, conductivity);
  Blynk.disconnect();

  // disconnect wifi
  //disconnectWifi();

  // delete emergency hibernate task
  vTaskDelete(hibernateTaskHandle);

  // go to sleep now
  hibernate();
}

void loop() {
  /// we're not doing anything in the loop, only on device wakeup
  delay(10000);
}

Here is the log from the console

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)<\r><\n>
configsip: 0, SPIWP:0xee<\r><\n>
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00<\r><\n>
mode:DIO, clock div:1<\r><\n>
load:0x3fff0018,len:4<\r><\n>
load:0x3fff001c,len:808<\r><\n>
load:0x40078000,len:6084<\r><\n>
load:0x40080000,len:6696<\r><\n>
entry 0x400802e4<\r><\n>
Initialize BLE client...<\r><\n>
Processing Flora device at c4:7c:xx:xx:xx:xx(try 1)<\r><\n>
- Connection successful<\r><\n>
- Found data service<\r><\n>
- Force device in data mode<\r><\n>
- Access characteristic from device<\r><\n>
- Read value from characteristic<\r><\n>
Hex: E6 0 0 FE 0 0 0 2B 1A 2 2 3C 0 FB 34 9B  <\r><\n>
-- Temperature: 23.00<\r><\n>
-- Moisture: 43<\r><\n>
-- Light: 254<\r><\n>
-- Conductivity: 538<\r><\n>
- Access battery characteristic from device<\r><\n>
- Read value from characteristic<\r><\n>
-- Battery: 99<\r><\n>
-- Firmware Version: 3.1.9<\r><\n>
Blynk connected.<\r><\n>
Going to sleep now.<\r><\n>
ets Jun  8 2016 00:22:57<\r><\n>
<\r><\n>
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)<\r><\n>
configsip: 0, SPIWP:0xee<\r><\n>
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00<\r><\n>
mode:DIO, clock div:1<\r><\n>
load:0x3fff0018,len:4<\r><\n>
load:0x3fff001c,len:808<\r><\n>
load:0x40078000,len:6084<\r><\n>
load:0x40080000,len:6696<\r><\n>
entry 0x400802e4<\r><\n>
Initialize BLE client...<\r><\n>
Processing Flora device at c4:7c:xx:xx:xx:xx (try 1)<\r><\n>
- Connection successful<\r><\n>
- Found data service<\r><\n>
- Force device in data mode<\r><\n>
- Access characteristic from device<\r><\n>
- Read value from characteristic<\r><\n>
Hex: E9 0 0 69 0 0 0 2B 15 2 2 3C 0 FB 34 9B  <\r><\n>
-- Temperature: 23.30<\r><\n>
-- Moisture: 43<\r><\n>
-- Light: 105<\r><\n>
-- Conductivity: 533<\r><\n>
- Access battery characteristic from device<\r><\n>
- Read value from characteristic<\r><\n>
-- Battery: 99<\r><\n>
-- Firmware Version: 3.1.9<\r><\n>
Blynk connection failed<\r><\n>
Going to sleep now.<\r><\n>
ets Jun  8 2016 00:22:57<\r><\n>
<\r><\n>
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)<\r><\n>
configsip: 0, SPIWP:0xee<\r><\n>
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00<\r><\n>
mode:DIO, clock div:1<\r><\n>
load:0x3fff0018,len:4<\r><\n>
load:0x3fff001c,len:808<\r><\n>
load:0x40078000,len:6084<\r><\n>
load:0x40080000,len:6696<\r><\n>
entry 0x400802e4<\r><\n>
Initialize BLE client...<\r><\n>
Processing Flora device at c4:7c:xx:xx:xx:xx (try 1)<\r><\n>
- Connection successful<\r><\n>
- Found data service<\r><\n>
- Force device in data mode<\r><\n>
- Access characteristic from device<\r><\n>
- Read value from characteristic<\r><\n>
Hex: EA 0 0 44 0 0 0 2B 14 2 2 3C 0 FB 34 9B  <\r><\n>
-- Temperature: 23.40<\r><\n>
-- Moisture: 43<\r><\n>
-- Light: 68<\r><\n>
-- Conductivity: 532<\r><\n>
- Access battery characteristic from device<\r><\n>
- Read value from characteristic<\r><\n>
-- Battery: 99<\r><\n>
-- Firmware Version: 3.1.9<\r><\n>
Something got stuck, entering emergency hibernate...<\r><\n>
Going to sleep now.<\r><\n>

you dont have Blynk.run() in loop

This is a deep sleep routine, it works differently as the code mostly runs in the setup.

Blynk and BT/BLE seem a bit unstable based on many recent topics… it is in beta, so getting as good a run as you are seems better than most.

I did not notice immediately that he disconnects the connection immediately after sending the data

Hm, but the BLE connection is working fine as it seems. The sensor is read continuously with some minor hiccups, even after the connection to Blynk via WiFi is already failing. So it rather seems to be an issue with WiFi, right?

I may have misunderstood how you are using BLE… if not for connecting to Blynk, which I guess makes sense now with using deep sleep, then the aforementioned beta issue with Blynk BLE is irrelevant.

And since I don’t deep sleep much… well , with my ESP stuff… personally, that’s a totally different story, I have trouble staying alert :tired_face: … thus I have nothing else to suggest, sorry.