Passively retrieve sensor data from some Xiaomi Bluetooth Low Energy (BLE) sensors.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Tim Weber 87aeb46688 Improve usage information, explain status 5 months ago
.gitignore Initial commit 5 months ago
LICENSE.txt Initial commit 5 months ago
README.md Improve usage information, explain status 5 months ago
example.py Initial commit 5 months ago
mpy_example.py Initial commit 5 months ago
xiaomi_ble_adv_parse.py Support negative temperatures 5 months ago

README.md

micropython-xiaomi-ble-adv-parse

Thanks to ESPHome, I’ve learned that some Xiaomi Bluetooth Low Energy (BLE) sensors broadcast their current values, which means you can retrieve them in a passive scan without even connecting to the device or draining the sensor battery.

ESPHome has support for reading these values built-in, but I have one or two projects running MicroPython and thus needed something to retrieve them from custom Python code. That’s what this project is for.

Status & contributing

This library does everything I personally need it to do, and I’m a bit hestitant to expand it. Please contact me (e.g. by opening an issue) before creating a pull request. If you’d like to create and maintain a fork with more features, let me know and I’ll probably link to it here.

Supported sensors

Currently, the only sensors I have tested this with are the ones called LYWSDCGQ by ESPHome.

I have also ordered a bunch of LYWSD03MMC sensors. These broadcast the data too, but with some encryption. The decryption logic has been reverse engineered (there’s also a Python script for decrypting), but it requires AES in CCM mode, which is currently not included in MicroPython.

You can flash them really easily to the custom ATC_MiThermometer firmware which doesn’t use encryption, or use something like ESPHome that already comes with the decryption code.

Since I’m going to use these sensors in an ESPHome setting, I probably won’t add support for them to this library.

Usage

See mpy_example.py for a complete MicroPython example of a scanner that logs the sensor data it sees. example.py is a more bare-bones example of how to parse raw binary data.

You need to pass the contents of a BLE advertisement package as bytes (or, even better, a memoryview) to parse_adv_data(). This data consists of one or more data blocks structured like this:

  • length of the block (1 byte)
  • type of the block (1 byte, we’re interested in 0x16)
  • variable length payload (we’re interested in ones with a UUID of 0xfe95)

If you’re using MicroPython: This is what your BLE handler will receive in data[4] (aka adv_data) on an _IRQ_SCAN_RESULT event. You should scan with active=False (the default).

See also example.py for examples of valid data from one of my sensors.

You’ll either get None back (if the data wasn’t understood or the sensor is not supported), or a dict with one or more of the following keys (depending on what the sensor sent at that time):

  • b: battery percentage (0 to 100)
  • t: temperature in degrees Celsius (e.g. 12.3)
  • h: relative humidity percentage (0.0 to 100.0)

Be aware that even a sensor that measures temperature and humidity and usually reports both these values simultaneously will most likely sometimes report just one of them. Your code should not rely on t and h always be present together.

Acknowledgements