15 minutes
Room temperature monitoring using Xiaomi temperature sensor, ESP32 and ESPHome
At home I have a few Shelly H&T sensors.
These sensors provide me with a regular update on the temperature and humidity in a room.
They look pretty nice and are tiny, so they can be placed just about anywhere without drawing too much attention.
They currently sell in a white/blue and a black/orange variant for about €24, with an optional USB-powered base replacing the CR123A battery sold for €5.
I have one of these on each floor for general temperature monitoring.
Recently, I came accross a video by Intermit.Tech (Quindor) on setting up temperature and humidity monitoring using cheap $4 Xiaomi sensors.
These sensors are also pretty tiny, but come with a LCD-screen displaying the sensor data.
Their sensor is also pre-calibrated and the devices are optimized for running on battery power.
Because of their small size, and more importantly their small price, they’re ideal for per-room temperature monitoring.

Since they send their data over Bluetooth Low-Energy (BLE) you’re supposed to use the companion app to get the readings.
In this blogpost I’ll explain how to add the Xiaomi thermometers to Home Assistant using an ESP32 board to capture the bluetooth data and ESPHome to import the data in Home Assistant. I’ll discuss flashing the Xiaomi LYWSD03MMC sensors with custom firmware, integrating the Xiaomi LYWSDCGQ, getting the bindkey for the Xiaomi CGG1 running the newer firmware, and setting the clock on the Xiaomi LYWSD02 without using the MiHome app.
Parts needed (shopping list) ¶
For this tutorial, you’ll need:
- One or more Xiaomi sensors.
They come in different shapes and sizes.
- Small square with LCD LYWSD03MMC
Note: These can (optionally) be flashed, see below. - Round with LCD LYWSDCGQ
Note: I did not test these yet - Round with E-ink CGG1
Note: You’ll need to obtain the bindkey via a modded app, see below. - Rectangular with E-ink LYWSD02
Note: These work out-of-the-box but you’ll need to set the clock.
- Small square with LCD LYWSD03MMC
- An ESP-board with BLE chip
- A USB power supply for the ESP32
- A micro-USB cable to to flash and power the ESP32
Flashing the ESP32 ¶
If you got a brand new ESP32 board, you’ll need to flash it once over USB to get it setup to work with ESPHome. Once this flashing is done, you’ll be able to push any future updates Over-The-Air (OTA).
ESPHome ¶
We’ll be writing our code for the ESP32 in ESPHome.
So make sure you’ve installed the ESPHome Add-on in Home Assistant.
The ESPHome website has a tutorial on installing this add-on in Home Assistant.
Flashing bluetooth discovery firmware ¶
In ESPHome, create a new device by clicking the big
+
button.
The details you enter here don’t matter too much. Just make sure you give it a reasonable name (this will also be used to name the config file). E.g.,livingroom_esp32
Now edit the device and overwrite the config with the following code. Change the back to what you originally named the device.
You can enter the WiFi credentials directly in the config, or make use of the secrets file (see below).substitutions: esphome_name: livingroom_esp32 esphome: name: ${esphome_name} platform: ESP32 board: mhetesp32devkit wifi: ssid: !secret wifi_ssid password: !secret wifi_pass api: reboot_timeout: 60min password: !secret esphome_api_pass # Sync time with HA time: - platform: homeassistant # Optional #web_server: # port: 80 ota: password: !secret esphome_ota_pass logger: # Enable Bluetooth scanning for this ESP32 esp32_ble_tracker:
Save and Close the editor.
Now click the 3 dots in the upper right corner of your device and click
Compile
.
This will compile the code into a firmware binary that we can download to our computer.While the code is compiling, download and install the ESPHome-Flasher for your system. This software will be used for the initial flashing over USB. Future updates will be done Over-The-Air (OTA).
We’ll now flash the compiled firmware to the ESP32.
- Connect the ESP32 using a micro-USB cable to your computer
- Open ESPHome-Flasher
- Click the refresh button at the top-right
- Select the COM port your ESP32 is connected to
- Browse to the firmware we’ve just compiled and download to our computer
- Click
Flash ESP
If the flashing software is unable to put the ESP32 in flash mode, hold down the Boot button on the ESP32 while it’s trying to flash.
Once the flashing has started, you can let go of the Boot button.Once it’s done flashing, the ESP32 will connect to your WiFi network and you’ll be able to control the ESP32 Over-The-Air using ESPHome.
Flashing sensor firmware ¶
You can now disconnect the ESP32 and install it where it will be able to receive the bluetooth data of your sensors. Power it using a phone charger, like the one in the Shopping List above.
- Back in the ESPHome dashboard, you can now click the
LOGS
button to view the output of the ESP32 board.
In the past you’d see broadcast messages containing temperature and humidity information, including the device’s MAC address. Nowadays you’ll need to look for linesFound device XX:XX:XX:XX:XX:XX (...) Name: 'xxxxxxxxxx'
. You’ll want to note down the MAC address of the ATC device (if flashed) or with the original name (e.g., LYWSD03MMC).BLE_tracker output
Note: To make identifying the correct Xiaomi device easier, make sure the others are out of bluetooth range or are turned off. You may also want to label each sensor after you’ve identified it. - We’ll now edit the device’s code again and add the sensor entities for the Xiaomi sensor(s) we’ll be monitoring.
Open the config editor and paste the following code below the code we already had:# Add this to the substitions block: # substitutions: sensor_name_lywsd03: Living room sensor_name_lywsd02: Kitchen sensor_name_cgg1: Master Bedroom sensor_name_lywsdcgq: Office switch: - platform: gpio name: "${esphome_name} - Onboard LED" pin: 2 inverted: True - platform: restart name: "${esphome_name} - Restart" id: restart_switch sensor: # General - platform: uptime name: "${esphome_name} - Uptime Sensor" - platform: wifi_signal name: "${esphome_name} - WiFi Signal" update_interval: 60s # LYWSD03MMC - Advertising Type: Mi Like - platform: xiaomi_lywsd03mmc mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor bindkey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Replace with bind key, use a dummy value when flashed with custom firmware temperature: name: "${sensor_name_lywsd03} - Temperature" humidity: name: "${sensor_name_lywsd03} - Humidity" battery_level: name: "${sensor_name_lywsd03} - Battery Level" # LYWSD03MMC - Advertising Type: Custom - platform: atc_mithermometer mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor temperature: name: "${sensor_name_lywsd03} - Temperature" humidity: name: "${sensor_name_lywsd03} - Humidity" battery_level: name: "${sensor_name_lywsd03} - Battery-Level" battery_voltage: name: "${sensor_name_lywsd03} - Battery-Voltage" # LYWSD02 - platform: xiaomi_lywsd02 mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor temperature: name: "${sensor_name_lywsd02} Temperature" humidity: name: "${sensor_name_lywsd02} Humidity" battery_level: name: "${sensor_name_lywsd02} Battery Level" # CGG1 - platform: xiaomi_cgg1 mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor bindkey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Replace with bind key, requires different ESPHome_version temperature: name: "${sensor_name_cgg1} Temperature" humidity: name: "${sensor_name_cgg1} Humidity" battery_level: name: "${sensor_name_cgg1} Battery Level" # LYWSDCGQ - platform: xiaomi_lywsdcgq mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor temperature: name: "${sensor_name_lywsdcgq} Temperature" humidity: name: "${sensor_name_lywsdcgq} Humidity" battery_level: name: "${sensor_name_lywsdcgq} Battery Level" # Remove or add extra sensors by deleting/copying any of the blocks above. # Change MAC address, bindkey and sensor names
- Press the
Upload
bottom at the bottom right of the editor.
This will save, compile and upload the new firmware to the ESP32 (OTA).
Storing WiFi creds and OTA/API passwords in secret file ¶
Just like with Home Assistant, ESPHome has a secrets.yaml
in which you can store stuff like WiFi credentials.
This allows you to keep secret data away from your config files and also adds consistency accross your devices.
To make things even easier, you can reference your Home Assistant secrets.yaml
from the ESPHome’s one, allowing you to keep everything in one central location.
Create a file /config/esphome/secrets.yaml
with the following content:
<<: !include ../secrets.yaml
Now in /config/secrets.yaml
you can add your WiFi credentials etc.
wifi_ssid: "MyVerySecretWiFiNetwork"
wifi_pass: "MyverySecretWiFiPassword"
esphome_ota_pass: "SecretEsphomeOtaPass"
esphome_api_pass: "SecretEsphomeApiPass"
You can now reference these secrets from your config using e.g. ssid: !secret wifi_ssid
.
Adding the sensors in Home Assistant ¶
Adding the sensors to Home Assistant is really easy. If the sensor for some reason doesn’t show up yet in the guide below, give Home Assistant a reboot and wait a few minutes.
- In Home Assistant, go to Configuration > Integrations.
- If the ESP32 isn’t automatically discovered yet by Home Assistant, click the big
+
button to add a new integration.
Choose ESPHome from the list. - Enter the IP address or hostname of your ESP32 board, keep the port in its default value.
- Enter your API and/or OTA password.
- Add the device to a room if you wish to do so.
Within the Configuration page you should now see an entry for your device (livingroom_esp32) under ESPHome.
Clicking this device will show you the different sensors for the temperature, humidity and battery level.
You should also have a switch to turn on the onboard LED (useful to identify the device) and to reboot it.
You may also have a sensor for the WiFi signal strength and device uptime.
It may take a while before sensor data will appear for the device.
Since the sensors are battery powered, it may take until a certain temperature change (or the next update interval).
Device specific configurations ¶
Getting the bindkey of the LYWSD03MMC and flashing custom firmware ¶
Sadly enough, more recent models of the Xiaomi (LYWSD03MMC) sensors come with a new firmware that encrypts the data send over bluetooth. Luckily Aaron Christophel came up with a nice way of hacking the firmware on these sensors. Not only does his hack provide a method of retrieving the bluetooth encryption key (allowing us to decrypt the data) but he even wrote his own firmware. Using Aaron’s ATC_MiThermometer firmware, you can also control the update interval, allowing you to choose sensor update frequency over battery life.
Update 2021-05-18: There’s a fork of Aaron’s firmware which appears to offer more functions including non-volatile storage and a better low power management. To use this version, follow the same steps as below but grab the binary from Victor’s repository.

Note: Flashing the custom firmware isn’t strictly necessary to get the sensor data imported into Home Assistant.
If you don’t feel like flashing the sensor, follow the guide below until step 5 and skip the rest of the flashing.
The flashing will be done from the browser a phone or tablet, since you need to connect to the sensor over bluetooth.
Use the default browser of the device or the Chrome browser.
If it doesn’t work with one device, try it again on another.
I had issues trying this on a OnePlus and Firefox. It succeeded using a Samsung Galaxy Tab and its default browser.
Get the
ATC_MiThermometer.bin
binary from Aaron’s GitHub and save it to your phone/tablet.Still on the GitHub page, at the top of the Readme documentation, you’ll find a link to the Web Flasher tool also written by Aaron. Open this link in the default/Chrome browser of your phone/tablet.
On the Web Flasher page, check the
Hide unsupported
checkbox and clickConnect
.From the popup that should now have appeared, select the sensor you want to flash. The name should match the device ID from the shopping list above (e.g.,
LYWSD03MMC
).
Once connected, the “Temp/Humi” field – located about halfway the webpage – should be displaying sensor readings. At the bottom of the page, the logs should also show the device having connected.Press the
Do activation
button.
A Mi Token and Mi Bind Key should appear a bit below the “Temp/Humi” field of the previous step.
Note these down (or copy them into an email, Google Keep note, …) in a way that you can easily get to them from your computer/laptop.
This token and key are what you need to import the Xiaomi sensor into Home Assistant without flashing the custom firmware.If you don’t want to flash the Xiaomi sensor with the custom firmware, stop here and continue with the next part.
Below the “Do activation” button, there’s a
Choose File
button.
Press this button and select theATC_MiThermometer.bin
you downloaded earlier.
Make sure to select the correct file here, or you may/will brick the sensor!Press the
Start Flashing
button.
You’ll see that status of the flashing appearing below the button. Don’t use the phone for now, it’ll only take a minute or so.Once the update is succesful, press the
Connect
button again and look for the flashed sensor.
The device should now appear asATC_xxxxxx
. The logs at the bottom of the page should show you that you’ve connected to the device.Using the newly acquired features, we can now change some settings on the device.
Note that the changes don’t always go through to the device, so press each button like 5 times to make sure it was set succesfully.- set the
Advertising Type
toMi Like
Note: Since ESPHome v1.16.0Advertising Type: Custom
is supported. - set the
Advertising Interval
to your liking. Shorter interval means shorter battery life but less detailed measurements.
- set the
Getting the bindkey of the CGG1 ¶

MiHome Mod app ¶
Note: These steps must be followed with an Android device
- Download the MiHome mod apk.
The site is in Russian, so use Google Translate to translate if needed. - Configure your device to allow installation of untrusted sources.
- While installing the app, grant permission to the local device storage
- Once you open the app, a new folder will be created:
/devicestorage/vevs
. - Close the app and create a new folder within this folder:
/devicestorage/vevs/logs
- Open the app again and login with your Mi account.
- Add the CGG1 in the app.
- The bindkey is now stored on your device.
Transfer/devicestorage/vevs/logs/misc/pairings.txt
to your computer (over USB/bluetooth). - Extract the bindkey from the file you just transfered.
The pairings.txt
will look like this:
Did: blt.4.xxxxxxxxxxxxx
Token: xxxxxxxxxxxxxxxxxxxxxxxx
Bindkey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Mac: xx:xx:xx:xx:xx:xx
ESPHome ¶
To use this bindkey in your configuration, you’ll need to load an adapted version of ESPHome.
Update 2021-05-18: Flameeyes’ code has been imported into the main ESPHome code base since ESPHome v1.17.1.
It’s no longer necessary to move to Flameeyes’ codebase to configure the bindkey
in your ESPHome config.
- Open the Supervisor Dashboard in Home Assistnat
- Click the ESPHome add-on and go to the Configuration tab
- Under “esphome_version” enter
Flameeyes:cgg1-enc
Change esphome_version
In the YAML this would look like:ssl: true certfile: fullchain.pem keyfile: privkey.pem esphome_version: 'Flameeyes:cgg1-enc' relative_url: ''
- Save and restart the add-on
You can now add a bindkey
to the config/firmware.
Update ESP32 ¶
If you already had your ESP32 configured, you’ll need to update it to the custom ESPHome_version.
- Open the ESPHome dashboard.
- You’ll see the Update symbol at the top-right of the device’s entry.
- To update, click the 3 dots at the top-right of your screen and click “Update All”.
Update All
Setting the clock on the LYWSD02 ¶

The LYWSD02 also displays the current time.
Normally you need to install the MiHome app to sync the time. But installing a Chinese app just to sync the time on your sensors, might seem a bit useless. Luckily, another fantastic Github user, saso5, created a simple web app that allows you to set the time on your LYWSD02.
- Visit https://saso5.github.io/LYWSD02-clock-sync/ with the same device you used to flash your LYWSD03.
- Pick your timezone (between UTC/GMT-12 and UTC/GMT+14)
- Click the
Update time
button - Select the LYWSD02 in the popup that appears and click
Connect
The time on your LYWSD02 should now be correct.
Make sure you close the browser tab and disconnect your device from the Xiaomi.
Otherwise your device will “claim” the Bluetooth connection and the ESP32 won’t be able to connect.
There’s a feature request on the ESPHome GitHub to have the LYWSD02 sync with an SNTP server.
Full ESP32 configuration ¶
The complete configuration file looks like this:
substitutions:
esphome_name: livingroom_esp32
sensor_name_lywsd03: Living room
sensor_name_lywsd02: Kitchen
sensor_name_cgg1: Master Bedroom
sensor_name_lywsdcgq: Office
esphome:
name: ${esphome_name}
platform: ESP32
board: mhetesp32devkit
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
api:
reboot_timeout: 60min
password: !secret esphome_api_pass
ota:
password: !secret esphome_ota_pass
# Sync time with HA
time:
- platform: homeassistant
# Optional
#web_server:
# port: 80
logger:
# Enable Bluetooth scanning for this ESP32
esp32_ble_tracker:
switch:
- platform: gpio
name: "${esphome_name} - Onboard LED"
pin: 2
inverted: True
- platform: restart
name: "${esphome_name} - Restart"
id: restart_switch
sensor:
# General
- platform: uptime
name: "${esphome_name} - Uptime Sensor"
- platform: wifi_signal
name: "${esphome_name} - WiFi Signal"
update_interval: 60s
# LYWSD03MMC - Advertising Type: Mi Like
- platform: xiaomi_lywsd03mmc
mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor
bindkey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Replace with bind key, use a dummy value when flashed with custom firmware
temperature:
name: "${sensor_name_lywsd03} - Temperature"
humidity:
name: "${sensor_name_lywsd03} - Humidity"
battery_level:
name: "${sensor_name_lywsd03} - Battery Level"
# LYWSD03MMC - Advertising Type: Custom
- platform: atc_mithermometer
mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor
temperature:
name: "${sensor_name_lywsd03} - Temperature"
humidity:
name: "${sensor_name_lywsd03} - Humidity"
battery_level:
name: "${sensor_name_lywsd03} - Battery-Level"
battery_voltage:
name: "${sensor_name_lywsd03} - Battery-Voltage"
# LYWSD02
- platform: xiaomi_lywsd02
mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor
temperature:
name: "${sensor_name_lywsd02} Temperature"
humidity:
name: "${sensor_name_lywsd02} Humidity"
battery_level:
name: "${sensor_name_lywsd02} Battery Level"
# CGG1
- platform: xiaomi_cgg1
mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor
bindkey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Replace with bind key, requires different ESPHome_version
temperature:
name: "${sensor_name_cgg1} Temperature"
humidity:
name: "${sensor_name_cgg1} Humidity"
battery_level:
name: "${sensor_name_cgg1} Battery Level"
# LYWSDCGQ
- platform: xiaomi_lywsdcgq
mac_address: "XX:XX:XX:XX:XX:XX" # Replace with MAC Address of sensor
temperature:
name: "${sensor_name_lywsdcgq} Temperature"
humidity:
name: "${sensor_name_lywsdcgq} Humidity"
battery_level:
name: "${sensor_name_lywsdcgq} Battery Level"
# Remove or add extra sensors by deleting/copying any of the blocks above.
# Change MAC address, bindkey and sensor names
Changelog ¶
- 2020-02-09 - Newer versions of CGG1 have encrypted Bluetooth messages. Flameeyes:cgg1-enc firmware adds support for bindkey.
- 2021-02-14 - ESPHome v1.16.0 adds support for ATC_MiThermometer using Advertising Type: Custom
- 2021-05-18 - Flameeyes:cgg1-enc merged into main ESPHome codebase to support CGG1 with bindkey. ATC_MiThermometer fork adds extra features.
Home Automation Home Assistant Xiaomi temperature humidity sensor ESP32 ESPHome bluetooth
2997 Words
2021-01-12 (Last updated: 2021-05-18)