Xiaomi offers very nice looking Temperature and Humidity thermostat which communicates over the Bluetooth – Xiaomi Mija BT. It is powered by one AA battery. It uses BLE technology what increases time of working.
Measurement is very accurate. I have 3 of them in each room. If you put them close together they show the same temperature and humidity. This is why I use them as a comparison to other sensors. Unfortunately they can’t be used outdoor unless temperature in your country doesn’t drop below zero degree.
OK they are nice looking sensors but how to integrate them with smart home. Well Xiaomi recommends to install own application and then it allows you to integrate with other devices. Moreover you have to set China location to get it in portfolio. Fortunately there is another option. I was looking support in OpenHAB nativel, however configuration using PaperUI was difficult and no stable. Sensors were detected than stopped update their status etc. It is constantly developed but I found much quicker and more stable solution, also I will be able to communicate over MQTT.
Requirements
There is a git project called https://github.com/tsymbaliuk/Xiaomi-Thermostat-BLE. As mentioned on the website:
Code for Raspberry Pi that parses BLE-packages from Xiaomi Thermostat and produces data in JSON format to output. Doesn’t establish any connection, works completelly passive, so the battery life remains the same. Works with both generations of sensors (Xiaomi and ClearGrass).
Download and compile it. Raspberry Pi 3+ has support for BLE 4.x it means that will be able to detect our sensors. I use Raspberry Pi 3 Zero and old laptop where I have OpenHAB installed. For laptop i purchased USB BT5.0 adapter like on the photo.
Compiling
1 |
g++ -std=c++11 -o xiaomiscan-orig xiaomiscan.cpp `pkg-config --cflags ncurses` -lbluetooth -lncurses |
It worked for rasbian but for linux on the laptop (Sabayon distro) I had to dowload bluez-5.47 and include in g++ path:
1 |
g++ -std=c++11 -o xiaomiscan-orig xiaomiscan.cpp `pkg-config --cflags ncurses` -lbluetooth -lncurses |
Scanning
Next step is scan your devices. You should get different information including BT address, temperature value, humidity value, temp and hum in one shot, also battery status from time to time:
1 2 3 4 5 6 7 8 |
sabayon /home/iot # ./xiaomiscan-orig Scanning.... { "id": 191, "mac":"4c65a8dd86dc", "type": 13, "temperature": 23.2, "humidity": 48.9 } { "id": 192, "mac":"4c65a8dd86dc", "type": 4, "temperature": 23.2 } { "id": 193, "mac":"4c65a8dd86dc", "type": 10, "battery": 72 } { "id": 194, "mac":"4c65a8dd86dc", "type": 13, "temperature": 23.1, "humidity": 48.7 } { "id": 89, "mac":"4c65a8da92d2", "type": 13, "temperature": 22.7, "humidity": 51.2 } { "id": 195, "mac":"4c65a8dd86dc", "type": 13, "temperature": 23.1, "humidity": 48.8 } |
It is nice however we can’t use it in either way. I have changed little bit code:
- support for scanning to specify BT address
- added parameter to get temperature value only
- added parameter to get humidity value only
- trying 200 times and after that quit – it prevents to hung when sensor is out of range.
Source code file is HERE.
Compile in the same way as before. I recommend to use different name for binary:
1 |
g++ -std=c++11 -o xiaomiscan xiaomiscanv2.cpp `pkg-config --cflags ncurses` -lbluetooth -lncurses -I /usr/src/bluez-5.47/lib/ |
When you scanned using original firmware you got a list of available sensors. It can happen that sensor is too far from BT adapter. I recommend to build more checkpoints. You can use existing Raspberry Pi 3 even they are configured normally for different purposes.
You know which BT address is available closely. Run then query specifically for temperature and humidity:
1 2 3 |
sabayon /home/iot # /usr/local/bin/xiaomiscan 4c65a8dd86dc hum 49.0sabayon /home/iot # /usr/local/bin/xiaomiscan 4c65a8dd86dc temp 23.1sabayon /home/iot # |
Cron and MQTT
We know how to use new command. Now there is a time to check it periodically and uplod data to mqtt server. I simply use cron + curl + OpenHAB Rest API. But lets start from beginning.
OpenHAB MQTT
.item file for Xiaomi Mijia BT sensors:
1 2 |
Number MJ_3_temp "Temperature bedroom MJ BT [%.1f ]" (gDashboard,GF_Bed,gGraph_Bed) {channel="mqtt:topic:mything:xiaomi3_temp" } Number MJ_3_hum "Humidity bedroom MJ BT [%.0f %%]" (gDashboard,GF_Bed,gGraph_Bed) {channel="mqtt:topic:mything:xiaomi3_hum" } |
.thing file for MQTT definition
1 2 3 4 5 6 7 |
Bridge mqtt:broker:localbroker [ host="10.0.1.10", secure=false, clientID="OpenHABv2" ] { Thing mqtt:topic:mything { Channels: Type number : xiaomi3_temp "Temperature MJ 3" [ stateTopic="/xiaomi3/temp", commandTopic="/xiaomi3/temp"] Type number : xiaomi3_hum "Humidity MJ 3" [ stateTopic="/xiaomi3/humidity", commandTopic="/xiaomi3/humidity"] } } |
Cron
Adding to cron checking periodically for status. It means scanning for Xiaomi Mijia sensor will be triggered at certain time and curl will send output of the scan to OpenHAB. OpenHAB will update state over MQTT.
1 2 |
*/3 * * * * /usr/bin/curl -X POST --header "Content-Type: text/plain" --header "Accept: application/json" -d `/usr/local/bin/xiaomiscan 4c65a8dd86dc temp` "http://10.0.1.10:8080/rest/items/MJ_3_temp" > /dev/null 2>&1 */3 * * * * /usr/bin/curl -X POST --header "Content-Type: text/plain" --header "Accept: application/json" -d `/usr/local/bin/xiaomiscan 4c65a8dd86dc hum` "http://10.0.1.10:8080/rest/items/MJ_3_hum" > /dev/null 2>&1 |
MQTT incoming updates:
1 2 3 4 5 6 7 8 9 |
sabayon /iot # /usr/local/bin/mosquitto_sub -v -h 10.0.1.10 -p 1883 -t '#' /xiaomi1/temp 22.7 /xiaomi1/humidity 50.7 /xiaomi2/temp 24.0 /xiaomi1/temp 22.7 /xiaomi1/humidity 50.6 /xiaomi3/temp 23.0 /xiaomi3/humidity 49.1 |
Crontab entries are example only. I put all sensors to one file and then put to cron as one script every minute. Scanning runs one by one which minimize chance to crash or hung.
Any comments welcome.
I have “segmentation fault”
Can you paste full command you execute? Have compiled mine source code or/and original one? Does original one worke?