Passively retrieve sensor data from some Xiaomi Bluetooth Low Energy (BLE) sensors.
You cannot 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 1 year ago
.gitignore Initial commit 1 year ago
LICENSE.txt Initial commit 1 year ago
README.md Improve usage information, explain status 1 year ago
example.py Initial commit 1 year ago
mpy_example.py Initial commit 1 year ago
xiaomi_ble_adv_parse.py Support negative temperatures 1 year ago

README.md

micropython-xiaomi-ble-adv-parse

Thanks to ESPHome, Ive 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. Thats what this project is for.

Status & contributing

This library does everything I personally need it to do, and Im a bit hestitant to expand it. Please contact me (e.g. by opening an issue) before creating a pull request. If youd like to create and maintain a fork with more features, let me know and Ill 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 (theres 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 doesnt use encryption, or use something like ESPHome that already comes with the decryption code.

Since Im going to use these sensors in an ESPHome setting, I probably wont 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, were interested in 0x16)
  • variable length payload (were interested in ones with a UUID of 0xfe95)

If youre 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.

Youll either get None back (if the data wasnt 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