Xiaomi Mi Temperature Humidity Sensor (MJ_HT) + ESP32 + Blynk

Hi Blynkers !

Here is the project I just finished, the goal was to connect the Xiaomi Temperature and Humidity sensor (that you can buy for around 12€) with Blynk through ESP32.

Code

#include <esp_log.h>
#include <string>
#include <sstream>
#include <sys/time.h>
#include <BLEDevice.h>

#include <BLEAdvertisedDevice.h>
#include <BLEClient.h>
#include <BLEScan.h>
#include <BLEUtils.h>
#include <sdkconfig.h>

#define BLYNK_PRINT Serial // Defines the object that is used for printing
#define BLYNK_DEBUG        // Optional, this enables more detailed prints
#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>

//WidgetRTC rtc;
BlynkTimer timer;
BLEClient* pClient;

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

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

#define MJ_ADDR "58:2D:34:31:F8:50"
static BLEAddress MJAddress(MJ_ADDR);
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
uint8_t* pData;
float temp;
float humi;
int n=0;
WidgetBridge bridge1(V10); //Initiating Bridge Widget on V1 of Device LolinD32

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
// The remote service we wish to connect to.
static BLEUUID serviceUUID("226c0000-6476-4566-7562-66734470666d");
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("226caa55-6476-4566-7562-66734470666d");

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.print("Notify callback for characteristic ");
    Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    Serial.print("data: ");
    Serial.println((char*)pData);
    temp = ((pData[2]-48)*10 + pData[3]-48 + (pData[5]-48)*0.1);
    Serial.println(temp);
    humi = ((pData[9]-48)*10 + pData[10]-48 + (pData[12]-48)*0.1);
    Serial.println(humi);
}

void sendSensorData(){
  Serial.println("Sending data to Blynk");
  Serial.println(temp);
  Serial.println(humi);
  Blynk.begin(auth, ssid, pass);
  Blynk.connect();
  bridge1.setAuthToken("BRIDGE TOKEN");
  Blynk.virtualWrite(V17, temp);
  Blynk.virtualWrite(V18, humi);
  bridge1.virtualWrite(V17, temp);
  bridge1.virtualWrite(V18, humi);
  delay(500);
  Blynk.disconnect();
  WiFi.mode(WIFI_OFF);
}


class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
    Serial.println("on connect");
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
    if (n==0){
      Serial.println("RESTART");
      ESP.restart();
    }
  }
};

void getSensorData1(){
  connectToServer(MJAddress);
}

void connectToServer(BLEAddress pAddress){
  n=0;
  Serial.println(" - Created client");
  pClient->setClientCallbacks(new MyClientCallback());
  Serial.println("=================== Forming a connection to Flora device ====================");
  Serial.println(pAddress.toString().c_str());
  Serial.println(" - Connection to MJ");
  pClient->connect(pAddress);
  n=1;
  Serial.println(" - Connected to MJ");

  // 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());
      pClient->disconnect();
    }
    Serial.println(" - Found our service");

    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID.toString().c_str());
      pClient->disconnect();
    }
    Serial.println(" - Found our characteristic");
    pRemoteCharacteristic->registerForNotify(notifyCallback);
    timer.setTimeout(10000L, sendSensorData);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting MJ client...");
  delay(500);
  BLEDevice::init("");
  pClient  = BLEDevice::createClient();
  delay(500);
  timer.setInterval(600000L, getSensorData1);
}

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

You can find your sensor’s address using “nRF Connect” app on your Smartphone and replace the address in the sketch
Of course, the bridge part is not mandatory.

3 Likes

How can i conect only to a local blynk raspbery server ?
I have 5 devices like this
https://www.amazon.de/Xiaomi-Bluetooth-Temperature-Humidity-Control/dp/B079XYJZ32
I search 4 days to ghet a solution

I forgot to specify that i have raspbery pi 3 b+ and esp32

Hi @bog, this is also the Xiaomi device I used.
I can’t tell how to use a local server, because I use Blynk Cloud server, and I have no clue how to use a local one.

Nevertheless, the code for the ESP32 in the 1st message can be adapted. What you might need to change :

  • Sensor address

#define MJ_ADDR "58:2D:34:31:F8:50"
Change it with address of your Xiaomi device (nRF Connect on Appstore/Playstore)

  • All Blynk related code, including function sendSensorData()

////////////////////////////////////
void setup() {
Serial.begin(115200);
Blynk.begin(auth, ssid, pass, IPAddress(192,xxx,x,xxx), 8080); /// i change here
Serial.println(“Starting MJ client…”);
delay(500);
BLEDevice::init(“”);
pClient = BLEDevice::createClient();
delay(500);
timer.setInterval(6000000L, getSensorData1);
}
/////////////////////////

This is my serial output
image

In my code, Blynk.begin is not called in setup() function.
Try to delete Blynk.begin from setup(), and put it into sendSensorData() function, as I did.

It’s workyng ! :slight_smile:
How can i implement the all 5 xiaomi ?
What tipe of code i can remove ?
Because the code is ocuping 75% with modified library .

First, set the “Partition Scheme” like my screenshot :

Next, you can remove Bridge related code if you don’t need it. You also can try to delete any libraries (like esp_log for example) and try if it’s still work. To be honest, I copied a code without checking if every library is needed.

To implement multiple sensors, you can declare multiple address’ :

static BLEAddress MJAddress(MJ_ADDR);
static BLEAddress MJAddress1(MJ_ADDR);
static BLEAddress MJAddress2(MJ_ADDR);
static BLEAddress MJAddress3(MJ_ADDR);
static BLEAddress MJAddress4(MJ_ADDR);

Then, you can call your function connectToServer(MJAddress1) when you want to have the data of the 2nd sensor, and repeat for the next sensor etc.

1 Like

can someone share the code for multiple sensors? Thx

Here is my example, but is far from being efficient; I’m using ESP32 with OLED and I’m sending data to my personal Blynk server:

#define BLYNK_PRINT Serial
#include <esp_log.h>
#include <string>
#include <sstream>
#include <sys/time.h>
#include <BLEDevice.h>
#include <BLEAdvertisedDevice.h>
#include <BLEClient.h>
#include <BLEScan.h>
#include <BLEUtils.h>
#include <sdkconfig.h>
#include <Wire.h>
#include "SSD1306.h"
SSD1306  display(0x3c, 5, 4);

#define BLYNK_PRINT Serial // Defines the object that is used for printing
#define BLYNK_DEBUG        // Optional, this enables more detailed prints
#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>

BlynkTimer timer;
BLEClient* pClient;
char auth[] = "NHMRKEYYJFbSqu-gyDGafnOn5MnnN7Or";
const char *senzori[6] = { "Init", "Hol Baie", "Living", "Hol Int", "Baie", "Living"}; 
int i = 0;
 
char ssid[] = "TNRAP5";
char pass[] = "1313131313";

#define MJ_ADDR2 "58:2D:34:31:0D:35" // 2
static BLEAddress MJAddress2(MJ_ADDR2);

#define MJ_ADDR3 "58:2D:34:33:71:87" //3
static BLEAddress MJAddress3(MJ_ADDR3);

#define MJ_ADDR1 "58:2D:34:33:70:B9" //1
static BLEAddress MJAddress1(MJ_ADDR1);

#define MJ_ADDR4 "58:2D:34:34:DB:45" //4
static BLEAddress MJAddress4(MJ_ADDR4);


//58:2D:34:33:70:B9 //1
//58:2D:34:31:0D:35 //2
//58:2D:34:33:71:87 //3
//58:2D:34:34:DB:45 // 4 CH

String oledTemp;
String oledHumi;

static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
uint8_t* pData;
float temp;
float humi;
int n=0;
static BLEUUID serviceUUID("226c0000-6476-4566-7562-66734470666d");
static BLEUUID    charUUID("226caa55-6476-4566-7562-66734470666d");
int sec;

void setup()
{
  Serial.begin(115200);
  delay(500);
  BLEDevice::init("");
  pClient  = BLEDevice::createClient();
  delay(500);
  timer.setInterval(50000L, getSensorData1);
  display.init(); //pt oled
  display.flipScreenVertically(); //pt oled
  Blynk.begin(auth, ssid, pass, IPAddress(192,168,0,170), 8080);
}

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    temp = ((pData[2]-48)*10 + pData[3]-48 + (pData[5]-48)*0.1);
       Blynk.virtualWrite(V17,temp);
    oledTemp = String(temp);
    humi = ((pData[9]-48)*10 + pData[10]-48 + (pData[12]-48)*0.1);
       Blynk.virtualWrite(V18,humi);
    oledHumi = String(humi);
         
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
 }
  void onDisconnect(BLEClient* pclient) {
    connected = false;
    if (n==0){
    ESP.restart();
    }
  }
};

void getSensorData1()
{
    if((sec/60) % 2 == 0)
   {
   i = 2;
   connectToServer(MJAddress3);
   }

    if((sec/60) % 2 == 1)
   {
   i = 1;
   connectToServer(MJAddress2);
   }
}

void connectToServer(BLEAddress pAddress){
  n=0;
  pClient->setClientCallbacks(new MyClientCallback());
  pClient->connect(pAddress);
  n=1;
  BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      pClient->disconnect();
    }
   pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
       pClient->disconnect();
    }
    pRemoteCharacteristic->registerForNotify(notifyCallback);
}

void oled()
{
          sec = (millis()/1000);
          display.clear();
          display.setFont(ArialMT_Plain_16);
          delay(100);
          display.drawString(0,18,"Temp: " + String(temp) + " °C");
          display.drawString(0,36,"Humi:  " + String(humi) + " %");
          display.setFont(ArialMT_Plain_10);
          if (sec % 4 == 0)
          {
            display.drawString(0,0,"  ");
          }
          if (sec % 4 == 1)
          {
            display.drawString(0,0," - ");
          }
           if (sec % 4 == 2)
          {
            display.drawString(0,0," --");
          }
           if (sec % 4 == 3)
          {
            display.drawString(0,0," -- > ");
          }
          display.drawString(88,0,senzori[i]); //8 pixeli latime pentru un caracter font 10
          display.display();
          Blynk.virtualWrite(V19,sec); 
          Blynk.virtualWrite(V20,senzori[i]); 
          delay(100); 
}

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

@cricri19top please edit your post, using the pencil icon at the bottom, and add triple backticks at the beginning and end of your code so that it displays correctly.
Triple backticks look like this:
```

Pete.

1 Like

@cricri19top despite me giving you some triple backticks to copy and paste, youve used different characters, which don’t work.
Please re-edit your code and use the correct triple backtick characters, otherwise your unformatted code will be deleted.

Pete.

1 Like

The thing I don’t like about your code is that you are clearing and re-writing your sensor data to your OLED display (and writing data to Blynk) every time the void loop is processed (which would normally be hundreds of times per second, but is being throttled to 5 times per second by the two 100ms delays).

However, your sensor data is changing much more slowly than this, so most of these OLED and Blynk actions are redundant as the data is the same.

A much more efficient way would be to have a function which re-writes your OLED and updates Blynk, and just call this function when the data from your sensors actually changes.

Pete.

1 Like

hı kaosss
my bad english soory

for esp32 it says the file is large

First of all, I’ll clean the loop

oled();

What does the message say when translated into English?

What upload setting did you use in the IDE, especially the choice of board type and how much memory to allocate to SPIFFS?

Pete.

The draft is too big; For tips on reducing size, visit: http://www.arduino.cc/en/Guide/Troubleshoot#size
Compile error for ESP32 Dev Module card.

thank you pete

Hi @muk, see my post about partition scheme : Xiaomi Mi Temperature Humidity Sensor (MJ_HT) + ESP32 + Blynk

You’ve chosen to allocate more than 50% of the available memory to SPIFFS, even though the sketch doesn’t use SPIFFS storage at all…

Pete.

Well spotted Pete !

1 Like