|
1 year ago | |
---|---|---|
.gitignore | 1 year ago | |
LICENSE.txt | 1 year ago | |
README.md | 1 year ago | |
example.py | 1 year ago | |
mpy_example.py | 1 year ago | |
xiaomi_ble_adv_parse.py | 1 year 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
to100
)t
: temperature in degrees Celsius (e.g.12.3
)h
: relative humidity percentage (0.0
to100.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
- Reverse engineering the MiBeacon protocol helped a lot in implementing the parser.