Mi Flora / Flower Care + Blynk + ESP32

Hi @igro123,

Firstly, in the second part of your post, this is not the the Serial Monitor return but the compiling/uploading log (which is not helpfull in our case). To answer @Blynk_Coeur post, the “Hard resetting via RTS pin” line at the end of upload is normal. Use the Serial Monitor, this is the first step to troubleshoot your code.

From your code, it should work for the 1st Flora Address but not the following Address’ : there is an ESP.restart(); at the end of void sendSensorData() function.

Basically, this is what you code does :

  • Run setup()
  • After 102 seconds, run getSensorData1()
  • Directly run getSensorData(floraAddress1, V6, V7);
  • Connect, get data and run sendSensorData(pin1, pin2);
  • Restart ESP with ESP.restart(); from the beginning

What if you put the ESP.restart(); at the end of getSensorData1() instead of sendSensorData() ?

It stays like this and nothing happens

19:05:35.274 -> =================== Forming a connection to Flora device ====================c4:7c:8d:6a:98:2c
19:05:35.305 ->  - Connection to Flora

Can you help me?

This is the code I’m using now:

#define BLYNK_PRINT Serial // Defines the object that is used for printing
#define BLYNK_DEBUG        // Optional, this enables more detailed prints
#include "BLEDevice.h"
#define alecrim "c4:7c:8d:6a:98:2c"
#define hortela "c4:7c:8d:6a:96:fd"
#define alface_manjericao "c4:7c:8d:6a:95:24"
#define cerejeira "c4:7c:8d:6a:93:7e"
#define serissa "c4:7c:8d:6a:94:a3"
#define jacare "c4:7c:8d:6a:93:cd"
#define BLYNK_NO_BUILTIN   // Disable built-in analog & digital pin operations
#include <Time.h>
#include <TimeLib.h>
#include "WiFi.h"
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  120        /* Time ESP32 will go to sleep (in seconds) */

BlynkTimer timer;
BLEClient* pClient;
//WidgetBridge bridge1(V10); //Initiating Bridge Widget on V1 of Device LolinD32

//**********TOKEN (OK)**********//
char auth[] = "xxxxxxf";

//**********WIFI (OK)**********//
char ssid[] = "xxxxx";
char pass[] = "xxxxxx";

// 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_sensor_data("00001a01-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_write_mode("00001a00-0000-1000-8000-00805f9b34fb");
static BLEAddress floraAddress1(alecrim);
static BLEAddress floraAddress2(hortela);
static BLEAddress floraAddress3(alface_manjericao);
static BLEAddress floraAddress4(cerejeira);
static BLEAddress floraAddress5(serissa);
static BLEAddress floraAddress6(jacare);
static BLERemoteCharacteristic* pRemoteCharacteristic;
float temp;
float moisture;
float light;
int conductivity;
int freeHeapstart;
int freeHeapstop;
int c;
 
void getSensorData(BLEAddress pAddress, uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4){ 
  btStart();
  timer.setTimeout(30000L, deepsleep);
  Serial.print("=================== Forming a connection to Flora device ====================");
  Serial.println(pAddress.toString().c_str());
  Serial.println(" - Connection to Flora");
  if (!pClient->connect(pAddress)){
      pClient->disconnect();
      delay(500);
      Serial.println(" - Cannot connect to Flora");
      ESP.restart();
  } else {
    Serial.println(" - Connected to Flora");
  }
  
  // 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());
  } else {
    Serial.println(" - Found our service");
  }
 
  pRemoteCharacteristic = pRemoteService->getCharacteristic(uuid_write_mode);
  uint8_t buf[2] = {0xA0, 0x1F};
  pRemoteCharacteristic->writeValue(buf, 2, true);
  
  // Obtain a reference to the characteristic in the service of the remote BLE server.
  pRemoteCharacteristic = pRemoteService->getCharacteristic(uuid_sensor_data);
  Serial.println(pRemoteService->toString().c_str());
  if (pRemoteCharacteristic == nullptr) {
    Serial.print("Failed to find our characteristic UUID: ");
    Serial.println(uuid_sensor_data.toString().c_str());
  } else {
      Serial.println(" - Found our characteristic");
    }
    
  // Read the value of the characteristic.
  std::string value = pRemoteCharacteristic->readValue();
  Serial.print("The characteristic value was: ");
  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(" ");

  temp = (val[0] + val[1] * 256) / ((float)10.0);
  moisture = val[7];
  light = val[3] + val[4] * 256;
  conductivity = val[8] + val[9] * 256;
  
  char buffer[64];

  temp = float(temp);
  moisture = float(moisture);
  light = float(light);
  conductivity = float(conductivity);
  
  Serial.print("Temperature: ");
  Serial.println(temp);

  Serial.print("Moisture: ");
  Serial.println(moisture);
  
  Serial.print("Light: ");
  Serial.println(light);
  
  Serial.print("Conductivity: ");
  Serial.println(conductivity);
  pClient->disconnect();
  delay(500);
  btStop();
  delay(500);
  sendSensorData(pin1, pin2, pin3, pin4);
}

void sendSensorData(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4) {
  Blynk.begin(auth, ssid, pass);
  do
{
  Blynk.connect();
} while (!Blynk.connected());
    //bridge1.setAuthToken("****************************");
    Blynk.virtualWrite(pin1, temp);
    Blynk.virtualWrite(pin2, moisture);
    Blynk.virtualWrite(pin3, light);
    Blynk.virtualWrite(pin4, conductivity);
    //bridge1.virtualWrite(V20, temp);
    //bridge1.virtualWrite(V21, moisture);
    delay(1000);
    Blynk.disconnect();
    WiFi.mode(WIFI_OFF);
    freeHeapstop = ESP.getFreeHeap();
    Serial.print("FREEHEAP END : ");
    Serial.println(freeHeapstop);
}

void getSensorData1(){
  getSensorData(floraAddress1, V6, V7, V8, V9);
  getSensorData(floraAddress2, V10, V11, V12, V13);
  getSensorData(floraAddress3, V14, V15, V16, V17);
  getSensorData(floraAddress4, V18, V19, V20, V21);
  getSensorData(floraAddress5, V22, V23, V24, V25);
  getSensorData(floraAddress6, V26, V27, V28, V29);
  ESP.restart();
}
void deepsleep(){
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(200);
  esp_deep_sleep_start();
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting Flora client...");
  delay(500);
  BLEDevice::init("");
  pClient  = BLEDevice::createClient();
  delay(500);
  WiFi.mode(WIFI_OFF);
  timer.setTimeout(102000L, getSensorData1);
}

void loop() {
  timer.run();
}

Hi @igro123, tried your code, works well for me :

12:48:21.164 -> Starting Flora client...
12:49:02.840 -> =================== Forming a connection to Flora device ====================c4:7c:8d:66:e9:11
12:49:02.840 ->  - Connection to Flora
12:49:03.309 ->  - Connected to Flora
12:49:04.632 ->  - Found our service
12:49:04.666 -> Service: uuid: 00001204-0000-1000-8000-00805f9b34fb, start_handle: 49 0x31, end_handle: 57 0x39
12:49:04.666 -> Characteristic: uuid: 00001a00-0000-1000-8000-00805f9b34fb, handle: 51 0x33, props: broadcast: 0, read: 1, write_nr: 0, write: 1, notify: 0, indicate: 0, auth: 0
12:49:04.700 -> Characteristic: uuid: 00001a01-0000-1000-8000-00805f9b34fb, handle: 53 0x35, props: broadcast: 0, read: 1, write_nr: 0, write: 1, notify: 1, indicate: 0, auth: 0
12:49:04.700 -> Characteristic: uuid: 00001a02-0000-1000-8000-00805f9b34fb, handle: 56 0x38, props: broadcast: 0, read: 1, write_nr: 0, write: 0, notify: 0, indicate: 0, auth: 0
12:49:04.700 ->  - Found our characteristic
12:49:04.734 -> The characteristic value was: Hex: E8 0 0 C3 0 0 0 0 0 0 2 3C 0 FB 34 9B  
12:49:04.734 -> Temperature: 23.20
12:49:04.734 -> Moisture: 0.00
12:49:04.734 -> Light: 195.00
12:49:04.734 -> Conductivity: 0
12:49:05.726 -> [44621] Connecting to ***************
12:49:07.778 -> [46666] Connected to WiFi
12:49:07.778 -> [46666] IP: ******************
12:49:07.778 -> [46666] 
12:49:07.778 ->     ___  __          __
12:49:07.778 ->    / _ )/ /_ _____  / /__
12:49:07.778 ->   / _  / / // / _ \/  '_/
12:49:07.778 ->  /____/_/\_, /_//_/_/\_\
12:49:07.813 ->         /___/ v0.6.1 on ESP32
12:49:07.813 -> 
12:49:07.813 -> [46672] Connecting to blynk-cloud.com:80
12:49:07.813 -> [46713] <[1D|00|01|00] ************************
12:49:07.847 -> [46735] >[00|00|01|00|C8]
12:49:07.847 -> [46735] Ready (ping: 21ms).
12:49:07.915 -> [46802] <[11|00|02|00]Fver[00]0.6.1[00]h-beat[00]10[00]buff-in[00]1024[00]dev[00]ESP32[00]build[00]Jun 16 2019 12:45:36[00]
12:49:12.854 -> [51736] Connecting to blynk-cloud.com:80
12:49:12.889 -> [51755] <[1D|00|01|00] *******************
12:49:12.889 -> [51774] >[00|00|01|00|C8]
12:49:12.889 -> [51774] Ready (ping: 17ms).
12:49:12.957 -> [51841] <[11|00|02|00]Fver[00]0.6.1[00]h-beat[00]10[00]buff-in[00]1024[00]dev[00]ESP32[00]build[00]Jun 16 2019 12:45:36[00]
12:49:12.990 -> [51861] >[00|00|02|00|C8]
12:49:13.024 -> [51911] <[14|00|03|00|0B]vw[00]6[00]23.200
12:49:13.091 -> [51980] <[14|00|04|00|0A]vw[00]7[00]0.000
12:49:13.157 -> [52048] <[14|00|05|00|0C]vw[00]8[00]195.000
12:49:13.225 -> [52115] <[14|00|06|00|06]vw[00]9[00]0
12:49:14.233 -> [53118] Disconnected
12:49:14.233 -> FREEHEAP END : 96704

So, I don’t know why it got stuck when connecting to your first Flora for you, but that is not a code issue. What I would do :

  • Check Flora address’
  • Try to switch first and second Flora (maybe the first one is defective)

Thank you to kaosss for sharing this sketch and the hard work that went into it. Just for anyone else that is wanting to use it:
1st issue I had, arduino complained it was missing timelib.h
Fixed this by downloading the full blynk library (see RTC Example not compiling)
2nd issue - Arduino said the sketch was too big for memory. (Sketch uses 1488370 bytes (113%) of program storage space. Maximum is 1310720 bytes). I have got around this for now by selecting Tools->Partition scheme -> HUGE APP (3MB No OTA/1MB SPIFFS). Hopefully that doesnt cause any issues for the sketch. There are some other partition schemes that I might be able to try if that does have issues. It has given me an initial reading from the flower care though, so thats a good start!

1 Like

Further follow up. I tried to sleep for 4 hours. So I set TIME_TO_SLEEP to 14400 seconds. Unfortunately the ESP32 wakes up every 2 minutes, reports the value and goes back to sleep. It does this for about 30 minutes. Then it goes to sleep and never wakes back up. Not sure if there is a limit to the amount of time we can sleep or if there is another issue…Going to try 2 hours and see if that makes any difference.

Hi @B1ynk, firstly, post your complete code.
The last code I posted (#5 post) has still a TIME_TO_SLEEP line but doesn’t use deepsleep. Yes, I was lazy to delete it :slight_smile:

1 Like

Ah OK. Thank you for that. Is that simply because you didnt want deepsleep or were there issues with it? Ill add a line of code in to try and send it to sleep to try it…

From what I remember, it was because I had issues with deepsleep (no wakeup issue for example)

1 Like

Just following up - I used the deep sleep code and added a few modifications -
Try to connect to bluetooth, if that didnt work, go to sleep for an hour, to stop it polling if the flower care was out of range or has a flat battery.
Read sensor data and send the four measurements to blynk.
Take the reading every 4 hours and go to deep sleep in between. This should mean very low power usage from the ESP32, not connecting to the flower care too often, which would increase its power usage but still getting good data.
After looking online a bit more though, I found that the raspberry pi versions that connect to the flower cares are also pulling the battery status and historical results too. I didnt want to use the raspberry pi, just because the ESP32 can use almost no power in deep sleep. So ideally now I want to get ESP32 to pull the historical data. I could then possibly pull that historical data once a day, at night for example, and wouldnt need to read the live data at regular intervals.

Latest update - I can now read the 4 sensor values as well as the firmware and battery and send that data to blynk. I also have the details on pulling the historical data. Historical data would be better as I could just read the data at the end of each day and send the daily data to blynk. The problem I have though is that blynk wont accept the timestamp data for the supergraph. So I cant graph the data. I could put the data in a table but that doesnt sound like a better option then my current approach of reading the live values 6 times a day. So Im abandoning at this stage unless I can find a way to graph the data. My deepsleep is using about 120uA @ 3.3V. Ill try and post my code soon in case anyone wants to use it.

1 Like

Superchart accepts data in real time and adds its own timestamp.
You can’t save up data and load it in a batch, so you would need to upload your reading when it’s taken.

Pete.

Hi, could you post the code for me?
I currently want to monitor the data of the sensor and also the battery.
Now I’ve been using the module which is esp32.

I am really confused. I am able to get 1 succesful reading from my Mi Flora sensor. After that the ESP32 is unable to connect via bluetooth until it is reset. It used to hang on connect(); after changing the waiting time in FreeRTOS.cpp, it does not hang, but also doesn’t get to a succesful connection, no matter how many attempts. Also creating a new BLEclient object each time does not help. I am not sure what is different with respect to the first time. Btw, I have dissabled the function related to Blynk, just focussing on getting the BLE connection to work right now.

I don’t want to be resetting my ESP32 after each sensor reading.

I need help with my project, where I want to control a submersible motor in a hydroponic set in a min and max range on one of the data of the mi flora sensor (I used conductivity). The steps that I have done are reading the data and send it to the Blynk.

The problem is how can I used the data in Blynk to send it to another device to control the motor. I read from links below and from Blynk website that I can use Eventor widget to trigger the motor but I’m still not sure how to code or setup for that.

I used Esp32 for my first device (to sensor detection) and esp8266 for my second device (to receive data from Blynk and control motor)

Here is my code that I have used from this site for my first device and it works for me

#define BLYNK_PRINT Serial         //Defines the object that is used for printing
#include "BLEDevice.h"
#define FLORA_ADDR "80:ea:ca:88:b0:bd"
#define BLYNK_NO_BUILTIN           //Disable built-in analog & digital pin operations
#include <Time.h>
#include <TimeLib.h>
#include "WiFi.h"
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#define uS_TO_S_FACTOR 1000000     //Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP  80          //Time ESP32 will go to sleep (in seconds)

BlynkTimer timer;
BLEClient* pClient;
WidgetBridge bridge1(V10); //Initiating Bridge Widget on V1 of Device LolinD32

//********BLYNK TOKEN**********//
char auth[] = "**********";

//**********WIFI***************//
char ssid[] = "**********";
char pass[] = "**********";

// 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_sensor_data("00001a01-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_write_mode("00001a00-0000-1000-8000-00805f9b34fb");
static BLEAddress floraAddress(FLORA_ADDR);
static BLERemoteCharacteristic* pRemoteCharacteristic;
float temp;
float moisture;
float light;
int conductivity;
int freeHeapstart;
int freeHeapstop;
int c;
 
void getSensorData(BLEAddress pAddress)       //FUNCTION 3
{    
  btStart();
  timer.setTimeout(30000L, deepsleep);        //FUNCTION 4 IN 3,,start in 30s
  Serial.println("========== Forming a connection to Flora device ==========");
  Serial.println(pAddress.toString().c_str());
  Serial.println(" - Connection to Flora");
  if (!pClient->connect(pAddress))
  { pClient->disconnect();
    delay(500);                               //delay 0.5s
    Serial.println(" - Cannot connect to Flora");
    ESP.restart();
  } 
  else 
  { Serial.println(" - Connected to Flora");
  }
  
  // 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());
  } 
  else 
  { Serial.println(" - Found our service");
  }
 
  pRemoteCharacteristic = pRemoteService->getCharacteristic(uuid_write_mode);
  uint8_t buf[2] = {0xA0, 0x1F};
  pRemoteCharacteristic->writeValue(buf, 2, true);
  
  // Obtain a reference to the characteristic in the service of the remote BLE server.
  pRemoteCharacteristic = pRemoteService->getCharacteristic(uuid_sensor_data);
  Serial.println(pRemoteService->toString().c_str());
  if (pRemoteCharacteristic == nullptr) 
  { Serial.print("Failed to find our characteristic UUID: ");
    Serial.println(uuid_sensor_data.toString().c_str());
  } 
  else 
  { Serial.println(" - Found our characteristic");
  }
    
  // Read the value of the characteristic.
  std::string value = pRemoteCharacteristic->readValue();
  Serial.print("The characteristic value was: ");
  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(" ");
  temp     = (val[0] + val[1] * 256) / ((float)10.0);
  moisture = val[7];
  light    = val[3] + val[4] * 256;
  conductivity = val[8] + val[9] * 256;
  
  char buffer[64];
  temp     = float(temp);
  moisture = float(moisture);
  light    = float(light);
  conductivity = float(conductivity);
  
  Serial.print("Temperature: ");
  Serial.println(temp);
  Serial.print("Moisture: ");
  Serial.println(moisture);
  Serial.print("Light: ");
  Serial.println(light);
  Serial.print("Conductivity: ");
  Serial.println(conductivity);
  
  pClient->disconnect();
  delay(500);           //delay 0.5s
  btStop();
  delay(500);           //delay 0.5s
  sendSensorData();     //FUNCTION 5 IN 3
}

void sendSensorData()   //FUNCTION 5 SEND DATA TO BLYNK
{ Blynk.begin(auth, ssid, pass);
  do
  { Blynk.connect();
  }
  while (!Blynk.connected());
  Blynk.virtualWrite(V6, temp);
  Blynk.virtualWrite(V7, moisture);
  Blynk.virtualWrite(V8, light);
  Blynk.virtualWrite(V9, conductivity);
  bridge1.virtualWrite(V11, conductivity);
  delay(5000);                       //delay 5s
  Blynk.disconnect();
  WiFi.mode(WIFI_OFF);
  freeHeapstop = ESP.getFreeHeap();
  Serial.print("FREEHEAP END : ");
  Serial.println(freeHeapstop);
  ESP.restart();
}

void getSensorData1()             //FUNCTION 2
{ getSensorData(floraAddress);    //FUNCTION 3 IN 2
}

void deepsleep()                  //FUNCTION 4
{ esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(200);                     //delay 0.2s
  esp_deep_sleep_start();
}

void setup()                      //FUNCTION 1
{                               
  Serial.begin(115200);
  Serial.println("Starting Flora client...");
  delay(500);                              //delay 0.5s
  BLEDevice::init("");
  pClient  = BLEDevice::createClient();
  delay(500);                              //delay 0.5s
  WiFi.mode(WIFI_OFF);
  timer.setTimeout(90000L, getSensorData1);//FUNCTION 2 IN 1 (start in 90s)
}

void loop() 
{ timer.run();
}

Eventor is a code free solution that is configured within the app (assuming that you’re using Android as its not available in iOS).

Personally, I’d avoid using Eventor and do it in your code.
You will need to use Bridge code to achieve thus, if you search the forum for Bridge then you’ll see a few tutorials.

Pete.

Hey is there any chance you can share the code you are using and the code you are using to get historical data? I would really appreciate it. I am working on a project to control an irrigation pump and have it working with one miflora and adafruit.io. I am switching it over to Blynk right now.

Hi Guys, I’m old (70 YO) but a beginner on this matter.
I have installed esp-idf and Arduino IDE and I’ve an ESP32 WROOM from AzDelivery and a couple of Flora sensor.
Your project is very appealing to start testing and learning about BLE.
Can you help me using your program with either IDF or Arduino?
Thanks a lot in advance. I believe that using something tested and functioning will create some entusiasm. Up to now I was unsuccesful.
I wait your suggestions as when I was waiting my first baby ;-))
Esperanto

I’d start by un-installing the esp-idf.

Then, if you haven’t already, install the ESP32 core for the Arduino IDE…

Follow the “Using Arduino IDE Boards Manager (preferred)” link.

Then, copy and compile the code from post #1, having chosen the correct board type in the IDE.

Pete.

Thanks Pete,
just few minutes ago I got answers from my Flora devices.
Now I’ve changed the address with one from my DWM devices (UWB sensors)
I’ve replaced the service UUIDwith the one of DWM and the static BLEUUID uuid_version_battery with (“80f9d8bc-3bff-45bb-a181-2d6a37991208”); which is one of the Characteristics of my device.
I get
Initialize BLE client…
Processing Flora device at fa:d2:e8:01:95:8c (try 1)

  • Connection successful
  • Found data service
  • Force device in data mode

Stack smashing protect failure!

abort() was called at PC 0x400dbb50 on core 1

Backtrace: 0x40093d74:0x3ffc94c0 0x40093fa5:0x3ffc94e0 0x400dbb50:0x3ffc9500 0x400d57e7:0x3ffc9520 0x400d5826:0x3ffc95e0 0x400d1bfe:0x89b06983

Rebooting…
ets Jun 8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee

I don’t understand why it crashes. The characteristic is just two bytes long.
Where should I start from with my search?

???

Pete.