Hi Blynkers !
I wanted to share with you the project I just finished. The goal of the project was to get the infos from de Xiaomi Flower Care and send them to Blynk from the ESP32.
Hardware
- Xiaomi Flower Care is a 4 in 1 Bluetooth sensor to put in your flower pot. It measures soil moisture, light intensity, soil fertility and temperature. Also, it is self-sufficient with a small battery !
- ESP32 is a “new” espressif chip that includes Wifi and Bluetooth, as ESP8266, developement boards including ESP32 are quite cheap, I personally use the LOLIN D32, and the Arduino IDE.
Tutorial
Here is a small tutorial to use the code provided in the last section:
- Add the ESP32 board and libraries in your Arduino IDE : https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/boards_manager.md
After following the instructions, you should find all ESP32 boards in Tools > Board, and have the ESP32 libraries from espressif available.
Here are the settings I use for the LOLIN D32
-
Add the ESP32_BLE_Arduino library from nkolban : https://github.com/nkolban/ESP32_BLE_Arduino
-
Now you need to know the address of your Flower Care (i.e mine is c4:7c:8d:66:e9:11). To do so, load the sketch BLE_scan.ino from the nkolban’s library in File > Examples > ESP32_BLE_ARDUINO. Run it near to your Flower Care, and you will have its address.
-
Now you have the Flower Care’s address, you can fill it in the code, with your Blynk Token, SSID and Password. Don’t change any UUID ! Upload it and it should work !
What it does ?
It switchs ON Bluetooth, reads the values from the sensor, switchs OFF bluetooth, switchs ON wifi, connects to Blynk, sends Temperature and Moistures values to V6 and V7 pins, disconnects from Blynk and switchs the wifi OFF. The routine is done every 10 minutes (600000 ms).
Why switching ON and OFF BT and Wifi ? Because the ESP32 cannot manage Bluetooth and Wifi at the same time, and when Blynk.run()
is in the loop, Wifi is “constantly” used. This is why the sketch does not look like a “standard Blynk sketch”.
Of course, you can change the sending period, and the vitrtual pins etc.
Edit 17/08 : I experienced heat issues that lead into an ESP32 crash when running during a “long” period, even with the use of WiFi/BT disconnect. I don’t really know the root cause, but I re-write a code deleting the timer and adding a DeepSleep. Both codes are below. Heat problem is solved now !
Code with Timer
Here is the code :
#include "BLEDevice.h"
#define FLORA_ADDR "c4:7c:8d:66:e9:11"
#define BLYNK_NO_BUILTIN // Disable built-in analog & digital pin operations
#include <TimeLib.h>
#include "WiFi.h"
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
BlynkTimer timer;
BLEClient* pClient;
//**********TOKEN (OK)**********//
char auth[] = "YOUR BLYNK TOKEN";
//**********WIFI (OK)**********//
char ssid[] = "YOUR WIFI SSID";
char pass[] = "YOUR WIFI PASSWORD";
// 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;
int moisture;
int light;
int conductivity;
int freeHeapstart;
int freeHeapstop;
void getSensorData1(BLEAddress pAddress){
btStart();
//delay(500);
Serial.print("============================ Forming a connection to Flora device ===============================");
Serial.print(pAddress.toString().c_str());
// Connect to the remove BLE Server.
if (!pClient->connect(pAddress)){
pClient->disconnect();
return;
} 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];
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();
timer.setTimeout(1000L,sendSensorData);
}
void sendSensorData() {
Blynk.begin(auth, ssid, pass);
//Blynk.run();
Blynk.connect();
Blynk.virtualWrite(V6, temp);
Blynk.virtualWrite(V7, moisture);
Blynk.disconnect();
WiFi.mode(WIFI_OFF);
freeHeapstop = ESP.getFreeHeap();
Serial.print("FREEHEAP END : ");
Serial.println(freeHeapstop);
}
void getSensorData() {
freeHeapstart = ESP.getFreeHeap();
Serial.print("FREEHEAP START : ");
Serial.println(freeHeapstart);
getSensorData1(floraAddress);
}
void setup() {
Serial.begin(115200);
Serial.println("Starting Flora client...");
BLEDevice::init("");
pClient = BLEDevice::createClient();
timer.setInterval(600000L,getSensorData);
}
void loop() {
timer.run();
}
Code with DeepSleep
#include "BLEDevice.h"
#define FLORA_ADDR "c4:7c:8d:66:e9:11"
#define BLYNK_NO_BUILTIN // Disable built-in analog & digital pin operations
#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 600 /* Time ESP32 will go to sleep (in seconds) */
BLEClient* pClient;
//**********TOKEN (OK)**********//
char auth[] = "YOUR TOKEN";
//**********WIFI (OK)**********//
char ssid[] = "YOUR WIFI SSID";
char pass[] = "YOUR WIFI PASSWORD";
// 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;
int moisture;
int light;
int conductivity;
int freeHeapstart;
int freeHeapstop;
void getSensorData(BLEAddress pAddress){
btStart();
//delay(500);
Serial.print("============================ Forming a connection to Flora device ===============================");
Serial.print(pAddress.toString().c_str());
// Connect to the remove BLE Server.
if (!pClient->connect(pAddress)){
pClient->disconnect();
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];
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();
}
void sendSensorData() {
Blynk.begin(auth, ssid, pass);
Blynk.connect();
Blynk.virtualWrite(V6, temp);
Blynk.virtualWrite(V7, moisture);
delay(500);
Blynk.disconnect();
WiFi.mode(WIFI_OFF);
// freeHeapstop = ESP.getFreeHeap();
// Serial.print("FREEHEAP END : ");
// Serial.println(freeHeapstop);
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // Setup wake up interval
delay(500);
esp_deep_sleep_start(); // Start deep sleep
}
void setup() {
Serial.begin(115200);
Serial.println("Starting Flora client...");
BLEDevice::init("");
pClient = BLEDevice::createClient();
delay(500);
getSensorData(floraAddress);
}
void loop() {
}
I hope it will be useful to someone, I struggled a bit before finding the way to manage wifi and bluetooth with this ESP32