XIAOMI Mijia Bluetooth Thermometer 2 integration

Hello all,
i am trying to integrate a XIAOMI Mijia Bluetooth Thermometer 2 device into my openhab 2 (runing on a RPI 3b+). I only have the sensors, no Xiaomi gateway.

I tried to use the bluetooth binding, however it is not detecting any device at all.
Using sudo bluetoothctl via SSH i can find and conncet the device to the RPI 3b+:

Can someone tell me how to connect the device to openhab 2?
I tried to search it on google and also hear but didnt find a valid info.

Thank you alot :slight_smile:

I guess this would be the prefered solution (you need a mqtt broker, too).

But I am not sure if the “Thermometer 2” is supported, yet.
You may want to start an issue there.

Hi Simon,
I have similar Mijia sensor (older version) and I am using python script to read temperature and humidity from it. The script uses bluepy library and sends the data using MQTT protocol.
To get the data into OH obviously you have to configure an MQTT thing.

Hi, thank you for the info.
Can you please post your code to get the data via bluepy from the sensor?

I would, but the thing is these both versions use different format of the data, so my script will not read proper values from your sensor. Try find something on the internet.

I don’t think devices other than “Xiaomi Mi Flora” are supported by this project.

Here is simple bash script to read data from this sensor: http://www.d0wn.com/using-bash-and-gatttool-to-get-readings-from-xiaomi-mijia-lywsd03mmc-temperature-humidity-sensor/

You are right.

I am using this fork:

I thought it would have been implemented in the original project already.

OpenMQTTGateway has it as test build, hopefully released in the master branch son.

Hi Simon,
I have similar Mijia sensor (older version) and I am using python script to read temperature and humidity from it. The script uses bluepy library and sends the data using MQTT protocol.
To get the data into OH obviously you have to configure an MQTT thing.

Hi druciak, thank you for the info.
I tried to follow this manual: Xiaomi Mijia Hygrothermo v2 sensor data on Raspberry Pi | Zsitko
However i am stuck at this point:

pi@hassbian:~/mitemp $ sudo blescan

Till then everything seems fine but then i am getting this error:

[11:54:53] openhabian@openhab:~/mitemp$ sudo blescan
Scanning for devices…
Traceback (most recent call last):
File “/usr/local/bin/blescan”, line 10, in
sys.exit(main())
File “/usr/local/lib/python3.7/dist-packages/bluepy/blescan.py”, line 122, in main
devices = scanner.scan(arg.timeout)
File “/usr/local/lib/python3.7/dist-packages/bluepy/btle.py”, line 852, in scan
self.start(passive=passive)
File “/usr/local/lib/python3.7/dist-packages/bluepy/btle.py”, line 797, in start
self._mgmtCmd(self._cmd()+“end”)
File “/usr/local/lib/python3.7/dist-packages/bluepy/btle.py”, line 312, in _mgmtCmd
raise BTLEManagementError(“Failed to execute management command ‘%s’” % (cmd), rsp)
bluepy.btle.BTLEManagementError: Failed to execute management command ‘scanend’ (code: 11, error: Rejected)

Dont know how to continue … :frowning:

Here is simple bash script to read data from this sensor: http://www.d0wn.com/using-bash-and-gatttool-to-get-readings-from-xiaomi-mijia-lywsd03mmc-temperature-humidity-sensor/

Running this i am getting this error:

[12:00:16] openhabian@openhab:~/mitemp$ gatttool --device=A4:C1:38:AD:3E:FA --char-write-req -a 0x10 -n 0100 --adapter=hci0 --listen
connect: Device or resource busy (16)

Try to execute

sudo hciconfig hci0 down && sudo hciconfig hci0 up

Read carefully the whole article. You have to first find out HW address of your sensor using hcitool. Then put this address to this command in --device parameter. Also it seems you have wrong characteristic handle in your command line, it should be “0x0038”, “0x10” is for version 1, which I have.

Thank you for the hint! I am now one step further :slight_smile:

Device (new): a4:c1:38:ad:3e:fa (public), -75 dBm
Flags: <06>
16b Service Data: <95fe30585b0559fa3ead38c1a408>
Complete Local Name: ‘LYWSD03MMC’

However again an error:

openhabian@openhab:~$ python3 mitemp/demo.py --backend bluepy poll a4:c1:38:ad:3e:fa
Getting data from Mi Temperature and Humidity Sensor
Traceback (most recent call last):
File “mitemp/demo.py”, line 96, in
main()
File “mitemp/demo.py”, line 92, in main
args.func(args)
File “mitemp/demo.py”, line 26, in poll
print(“FW: {}”.format(poller.firmware_version()))
File “/home/openhabian/mitemp/mitemp_bt/mitemp_bt_poller.py”, line 106, in firmware_version
self.battery = int(ord(res_battery))
TypeError: ord() expected a character, but string of length 15 found

Do you have an idea how to handle this?
Thank you!

Thank you, i receive now these values:

openhabian@openhab:~$ gatttool --device=A4:C1:38:AD:3E:FA --char-write-req -a 0x0038 -n 0100 --adapter=hci0 --listen
Characteristic value was written successfully
Notification handle = 0x0036 value: 4f 09 4b a5 0a
Notification handle = 0x0036 value: 50 09 4c a5 0a
Notification handle = 0x0036 value: 4d 09 4b a5 0a

However when i use the bash script like written in the manual:

#!/bin/bash
bt=$(timeout 15 gatttool -b A4:C1:38:AD:3E:FA --char-write-req --handle=‘0x0038’ --value=“0100” --listen)
if [ -z “$bt” ]
then
echo “The reading failed”
else
echo “Got data”
echo $bt temphexa=$(echo $bt | awk -F ’ ’ ‘{print $12$11}’| tr [:lower:] [:upper:] )
humhexa=$(echo $bt | awk -F ’ ’ ‘{print $13}’| tr [:lower:] [:upper:])
temperature100=$(echo “ibase=16; $temphexa” | bc)
humidity=$(echo “ibase=16; $humhexa” | bc)
echo “scale=2;$temperature100/100”|bc
echo $humidity
fi

i get the following output:

openhabian@openhab:~$ sudo bash xiaomi_sensor.sh
Got data
Characteristic value was written successfully Notification handle = 0x0036 value: 4e 09 4c a5 0a Notification handle = 0x0036 value: 4c 09 4c a5 0a temphexa=094E
(standard_in) 1: syntax error
76

It seems your temperature is 23.83 degrees and humidity is 75% :slight_smile:

There is a bug in this script, in line after “Got data”, there should be new line after “echo $bt”. After correction the script works.

There is a bug in this script, in line after “Got data”, there should be new line after “echo $bt”. After correction the script works.

Great, you are right, it works!
Thank you a lot for your support :slight_smile:

[08:19:46] openhabian@openhab:~$ sudo bash xiaomi_sensor.sh
Got data
Characteristic value was written successfully Notification handle = 0x0036 value: f5 08 4c 1d 0b Notification handle = 0x0036 value: f8 08 4c 1d 0b Notification handle = 0x0036 value: f6 08 4c 1d 0b
22.93
76

I am glad I could help. If you prefer python, here is the script I use, but it is for version 1. I think it requires only few changes to work with version 2.

#!/usr/bin/env python3

import re
import json
import logging
from bluepy.btle import *
from paho.mqtt import publish

logging.basicConfig(format='%(asctime)s: %(message)s', level=logging.DEBUG)

class XiaomiHygroThermoSensor:

    def __init__(self, mac):
        self._data = {}
        try:
            self.p = Peripheral(mac)
            self.p.setDelegate(XiaomiHygroThermoDelegate())
            logging.debug('Connected')

        except BTLEException:
            self.p = None
            raise

    def read_data(self, full_read = False):
        if self.p is None:
            return False

        try:
            if full_read:
                self.name = ''.join(map(chr, self.p.readCharacteristic(0x3)))
                self.firmware = ''.join(map(chr, self.p.readCharacteristic(0x24)))
                self.battery = self.p.readCharacteristic(0x18)[0]
            self.p.writeCharacteristic(0x10, bytearray([1, 0]), True)
            while not self.p.waitForNotifications(15.0):
                continue
            self.temperature = self.p.delegate.temperature
            self.humidity = self.p.delegate.humidity
            return True

        except BTLEException as e:
            self.p.disconnect()
            raise

    def disconnect(self):
        self.p.disconnect()


class XiaomiHygroThermoDelegate:

    def __init__(self):
        self.temperature = None
        self.humidity = None
        self.received = False

    def handleNotification(self, cHandle, data):
        if cHandle == 14:
            m = re.search('T=([\d\.]*)\s+?H=([\d\.]*)', ''.join(map(chr, data)))
            self.temperature = m.group(1)
            self.humidity = m.group(2)
            self.received = True

if __name__=="__main__":
    full_read = False
    if len(sys.argv) < 3:
        print('Provide sensor MAC and location')
        exit(0)
    if len(sys.argv) > 3:
        full_read = True

    sensor = XiaomiHygroThermoSensor(sys.argv[1])
    location = sys.argv[2]
    if sensor.read_data(full_read):
        mqtt_data = {"temperature": float(sensor.temperature), "humidity": float(sensor.humidity)}
        if full_read:
            mqtt_data.update({"battery": sensor.battery, "name": sensor.name, "version": sensor.firmware})
        logging.info(mqtt_data)
        msgs = [
            {"topic": "mijia/{}".format(location), "payload": json.dumps(mqtt_data)},
        ]
        publish.multiple(msgs, hostname="my.mqtt.server", auth={"username": "mqtt_user_name", "password": "mqtt_user_pass"})

    sensor.disconnect()

For sure it requires changes after if full_read: and in handleNotification method. I hope you find it useful.

Took a look at this library. In my opinion it is for version 1, that’s why you get errors.

Try this:

#!/usr/bin/env python3

import re
import json
import logging
from bluepy.btle import *
from paho.mqtt import publish

logging.basicConfig(format='%(asctime)s: %(message)s', level=logging.DEBUG)

class XiaomiHygroThermoSensor:

    def __init__(self, mac):
        self._data = {}
        try:
            self.p = Peripheral(mac)
            self.p.setDelegate(XiaomiHygroThermoDelegate())
            logging.debug('Connected')

        except BTLEException:
            self.p = None
            raise

    def read_data(self, full_read = False):
        if self.p is None:
            return False

        try:
#            if full_read:
#                self.name = ''.join(map(chr, self.p.readCharacteristic(0x3)))
#                self.firmware = ''.join(map(chr, self.p.readCharacteristic(0x24)))
#                self.battery = self.p.readCharacteristic(0x18)[0]
            self.p.writeCharacteristic(0x0038, bytearray([1, 0]), True)
            while not self.p.waitForNotifications(15.0):
                continue
            self.temperature = self.p.delegate.temperature
            self.humidity = self.p.delegate.humidity
            return True

        except BTLEException as e:
            self.p.disconnect()
            raise

    def disconnect(self):
        self.p.disconnect()


class XiaomiHygroThermoDelegate:

    def __init__(self):
        self.temperature = None
        self.humidity = None
        self.received = False

    def handleNotification(self, cHandle, data):
		logging.debug('Got notification' + str(cHandle))
		self.temperature = int.from_bytes(data[0:2],byteorder='little',signed=True)/100
		self.humidity = int.from_bytes(data[2:3],byteorder='little')
		logging.debug('Temperature: ' + str(self.temperature))
		logging.debug('Humidity: ' + str(self.humidity))
		self.received = True

if __name__=="__main__":
    full_read = False
    if len(sys.argv) < 3:
        print('Provide sensor MAC and location')
        exit(0)
    if len(sys.argv) > 3:
        full_read = True

    sensor = XiaomiHygroThermoSensor(sys.argv[1])
    location = sys.argv[2]
    if sensor.read_data(full_read):
        mqtt_data = {"temperature": float(sensor.temperature), "humidity": float(sensor.humidity)}
        if full_read:
            mqtt_data.update({"battery": sensor.battery, "name": sensor.name, "version": sensor.firmware})
        logging.info(mqtt_data)
        msgs = [
            {"topic": "mijia/{}".format(location), "payload": json.dumps(mqtt_data)},
        ]
        publish.multiple(msgs, hostname="my.mqtt.server", auth={"username": "mqtt_user_name", "password": "mqtt_user_pass"})

    sensor.disconnect()

Another solution below :

With this custom LYWSD03MMC firmware (supported by OpenMQTTGateway), the LYWSD03MMC advertises its data without encryption, so no need to connect to the sensor when using it. The data are read every BLEinterval, 55s per default, like all the other devices that advertise data.

Note that the device flashing process takes less than 5minutes and is done over the air (impressive :-)).

4 Likes