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>