sputnikdev / eclipse-smarthome-bluetooth-binding

Eclipse SmartHome Bluetooth Binding
46 stars 10 forks source link

Test and add support for Xiaomi Mi Flora Monitor #19

Closed vkolotov closed 6 years ago

vkolotov commented 6 years ago

Check if the device conform to standard GATT specifications and works out of the box.

jerano commented 6 years ago

Let me know if you need any help testing this, I've got three Mi Floras.

Successfully installed the Bluetooth Binding and the TinyB Binding yesterday, and they were discovered and added to my test-system. The following channels were detected/added: Online Connected Connection Control Connected Adapter RSSI Estimated Distance Nearest Adapter Location

Would be awesome getting them supported, so I don't have to bother with external scripts and stuff for getting the data.

vkolotov commented 6 years ago

hi @jerano, I'm working on this at the moment. It will be supported in the next release. I've got one sensor, so it is easier for me now.

jerano commented 6 years ago

awesome! then I can hold off on using some alternative way to get the sensors into my OH system.

keep up the good work!

vkolotov commented 6 years ago

Unfortunately MiFlora sensor (and probably other Mi sensors) uses a proprietary authentication mechanism that involves a handshake, security token generation/exchange. Here are some steps that have been captured by a bluetooth sniffer while a MiFlora sensor was getting connected:

Step 1. Authentication process begins
write   0x0013 01 00                - enable notification for 0x0012
Step 2. Session opens (a magic number {00 BC 43 CD} is written to 0x001B)
write   0x001B 00 BC 43 CD          - 00000010-0000-1000-8000-00805f9b34fb
notify  0x0012 CD 9B 00 FA          - 00000001-0000-1000-8000-00805f9b34fb
Step 3. Security tokens is generated and written
write   0x0012 10 A1 FB D5          - 00000001-0000-1000-8000-00805f9b34fb
some kind of response after sending an auth token
notify  0x0012 D0 55 DE 70          - 00000001-0000-1000-8000-00805f9b34fb
notify  0x0012 D0 55 DE 70          - 00000001-0000-1000-8000-00805f9b34fb
write   0x0013 00 00                - disable notification for 0x0012
authentication complete
 -----
read    0x0038 -> 63 27 33 2E 31 2E 38         - 00001a02-0000-1000-8000-00805f9b34fb
write   0x0036 01 00                - enable notif for data char 0x0035 (00001a01-0000-1000-8000-00805f9b34fb)
write   0x003F 01 00                - enable notif for 0x003E (00001a10-0000-1000-8000-00805f9b34fb)
write   0x0033 A0 1F                - set the magic number (00001a00-0000-1000-8000-00805f9b34fb) to be able to read the data char (00001a01-0000-1000-8000-00805f9b34fb))
notify   0x0035 0E 01 00 4E 01 00 00 00 00 00 02 3C 00 FB 34 9B - data char
read        0x0041 -> 1C 04 08 00       - (00001a12-0000-1000-8000-00805f9b34fb)
write   0x003E A0 00 00             - 00001a10-0000-1000-8000-00805f9b34fb
notify   0x003E A0 00 00             - 00001a10-0000-1000-8000-00805f9b34fb
read        0x003C -> 00 00 00 00 C6 13 08 00 C8 15 08 00 00 00 00 00 (00001a11-0000-1000-8000-00805f9b34fb)
write    0x003E A2 00 00
write    0x003F 00 00               - disable for 0x003e
notify   0x0021 00                  - 00001001-0000-1000-8000-00805f9b34fb
notify  0x0035 0D 01 00 97 01 00 00 00 00 00 02 3C 00 FB 34 9B - data
write    0x0036 00 00               - disable for 0x0035
write   0x0033 C0 1F                - set the magic number - different to previous one
read        0x0038 -> 63 27 33 2E 31 2E 38         00001a02-0000-1000-8000-00805f9b34fb
write   0x0036 -> 01 00             - enable notif for data
write   0x0033 -> A0 1F             - magic number again
notify   0x0035 -> 0C 01 00 2B 01 00 00 00 00 00 02 3C 00 FB 34 9B - data
notify   0x0021 00                  - ??? 00001001-0000-1000-8000-00805f9b34fb
notify   0x0035 ...
notify   0x0035 ...

Unfortunately there is not any easy way to generate security tokens, the Flower Care android mobile app uses a JNI library to generate/encrypt tokens. The authentication process is happening in BleRegisterConnector class (Flower Care app). There are three steps in total (see above). Security tokens are generated by BLECipher class which it turns uses a JNI library "blecipher". It is possible to extract that library from the mobile app (see BLECipher and generateToken), however it won't work in linux. Looks like android libs are not compatible with other distributions of linux. The following error happens when you try to use it in ubuntu: java.lang.UnsatisfiedLinkError: /home/user/projects/libblecipher.so: /usr/lib/x86_64-linux-gnu/libm.so: invalid ELF header Furthermore, in order to read the data characteristic ("00001a01-0000-1000-8000-00805f9b34fb"), a special magic number ({0xA0, 0x1F}) must be set to a characteristic first ("00001a00-0000-1000-8000-00805f9b34fb").

If authentication token is not validated by device, device drops connection. However, fortunately it is still possible to quickly read data characteristic before it disconnects.

In other words, we won't be able to create a proper binding for Mi devices (unless someone figures out how to encrypt security tokens), however we still can create a binding that periodically connects to the device and fetches data while it is in authentication process (like other python scripts do).

jerano commented 6 years ago

There's no checking of firmware version before that? I mean, it might be something they've implemented later, and us lucky ones with earlier versions (not using the app at all!) aren't affected by this!(?)

Just speculating though... I think I've noticed the sensor disconnecting after a while, when playing around with gatttool and other bluetooth tools.

Anyways, if it's possible to implement a small binding for them, I think lots of people would be happy, but if not... we'll just have to stick to scripts scraping the info and updating OH from outside.

Thanks for the work you put into this!!

vkolotov commented 6 years ago

There's no checking of firmware version before that? I mean, it might be something they've implemented later, and us lucky ones with earlier versions (not using the app at all!) aren't affected by this!(?)

Indeed it might be like that. Unfortunately I have upgraded the device I have and I can't check now. Would you @jerano be able to double check this theory? E.g. use a gattool or bluetoothctrl to connect to the device and see if it disconnects after 5-10 secs?

jerano commented 6 years ago

Hey @vkolotov !

With bluetoothctl, connection to a sensor seems to disconnect after 5-10secs, unfortunately. Firmware on my sensors are v2.6.2.

Can read characteristics from sensor with gatttool, ie. like: gatttool -i hci0 -b xx:xx:xx:xx:xx:xx --char-read --handle=0x0035 But sometimes it times out (I assume) with "connect error: Transport endpoint is not connected (107)"

Oh well, it seems there are some decent ways to get the sensor data into OH via ie. MQTT, so if no specific binding for these sensors are created, I guess we'll survice...

vkolotov commented 6 years ago

I'm planning to create a bluetooth extension for this device anyway, it will allow us to use miflora with no issues, like if there was not that stupid auth mechanism, it just won't be efficient implementation-wise.

vkolotov commented 6 years ago

Support for this device has been added in v1.1

drndos commented 5 years ago

https://github.com/aprosvetova/xiaomi-kettle is getting really close to the solution to your problem