Xiaomi sensors/appliances

Posted on
  • Hi all, just want to share a code snippet and some thoughts/ideas on how to interact with Xiaomi devices.

    There are a few Xiaomi devices that have internal bluetooth module, e.g.:

    • Mi Flora plant sensor
    • Temperature and Humidity sensor
    • Mi Smart Scale
    • Mi Smart Kettle

    Xiaomi uses its own proprietary authentication protocol in their devices. The protocol logic is encapsulated into a native shared library (Android JNI library) that is used to generate/encode/decode authentication tokens which must be exchanged with the central device. Xiaomi devices only allow a very short lived connection while they are expecting to receive an authentication token. Once authentication fails, device drops its connection. More info on the Xiaomi authentication protocol can be found here. Fortunately, Xiaomi devices actively advertise their data which can be easily received and decoded.

    It turns out that all Xiaomi devices (that I'm aware of) use a common protocol/data structure for their advertisement messages that can be easily decoded, hence no need in establishing any direct connection with the device. I've decoded them and came up with some custom GATT definitions that describes the protocol and data structure here and here.

    Here is a code snippet that shows how to decode Temperature and Humidity sensor data:

    var temp = null;
    var humidity = null;
    var battery = null;
    
    function getSensorData() {
        NRF.findDevices(function(devices) {
                if (devices[0] && devices[0].serviceData.fe95) {
                    var data = devices[0].serviceData.fe95;
                    var flag = data[11];
                    switch (flag) {
                        case 4: {
                            // temp
                            temp = (data[14] | data[15] << 8) / 10;
                            break;
                        }
                        case 6: {
                            // humidity
                            humidity = (data[14] | data[15] << 8) / 10;
                            break;
                        }
                        case 10: {
                            // battery
                            battery = devices[0].serviceData.fe95[14];
                            break;
                        }
                        case 13: {
                            // temp and humidity
                            temp = (data[14] | data[15] << 8) / 10;
                            humidity = (data[16] | data[17] << 8) / 10;
                            break;
                        }
                        default : {
                            print("Unknown flag: " + flag);
                        }
                    }
                }
                for (var i = 0; i < devices.length; i++) {
                    devices[i] = null;
                }
                devices = null;
            }, {
                filters: [
                    { id: "4c:65:a8:d0:7a:ee public" }
                ],
                timeout: 2000
            }
        );
    }
    
    setInterval(function () {
        print("Temp: " + temp + " humidity: " + humidity + " battery: " + battery);
        getSensorData();
    }, 5000);
    

    As I mentioned, all devices share the same notification data structure, hence it is easy to come up with very similar code that would decode advertisements from other Xiaomi devices by following the gatt specs that I provided.

    PS. The provided gatt spec files is a part of Gatt Parser, Java Bluetooth Manager and Eclipse SmartHome binding that I'm working on, you may find it useful too. The official discussion thread here.

    Let me know if you have any questions.

  • This is great - thanks for posting it up separately to your other stuff! I've been meaning to try one of those Xiaomi Plant moisture sensors for ages, and this gives me a good excuse :)

    If you're interested, you should be able to change the last part of NRF.findDevices to:

            }, {
                filters: [
                    {serviceData:{"fe95":{}}}
                ],
                timeout: 2000
            }
    

    which will automatically filter out only devices that advertise that service data - it's a bit faster and more efficient with memory if there are a bunch of BLE devices.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Xiaomi sensors/appliances

Posted by Avatar for Vlad @Vlad

Actions