Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
This story started from my Facebook post where we was talking about problem of the absence of API for fitness trackers, and why thatâs not helping data scientist to make cool stuff for them.
After that post my friend Volodymyr Shymanskyy tried to help me and found some code on github from Leo Soares for my fitness tracker MiBand 2. He tried to run it, but there was some problems with connection, so he take few hours to fix it. After that he commit it and sent me a link.
That was my starting point, which already was pretty good. At that time code was giving possibility to connect to band, run notifications, and get one-shoot heart measurement. But that was not enough for me, cause i want to get real-time raw data from sensors to use it in my data science experiments (want to make gym exercise predictor).
And the fun part begunâŠ
Before this i didnât have any experience on working with BLE devices, so first i tried to understand how all this stuff organized and work. As as it turned out it was pretty simple.
Each BLE device has few services, each of them having characteristics, and some of the characteristics having descriptors(if characteristic has more then one param or type of work(read|notification)). Some of the Characteristics is having only read/write access, like current time, battery status or revision info. Some of them more complicated and working through request/notification loop, for example real-time heart rate monitor or authorization. And basically that all you need to know to start working with it.
Also you will need two apps that will help you debug BLE deviceâââWireshark protocol analyzer and BLE debugger. And you will need to get access to your android phone developer options (sorry iOS guys i donât know how to handle this on your side).
To start, you will need to unpair your MiBand2 from phone app.
So letâs see now what services and characteristics our band has. Letâs open BLE debugger, and run scan, you will see something like this
Save your device MAC address somewhere, we will need it farther.
Now letâs connect to it and see what services and characteristics does it have.
From this two simple operations we already got some useful info about our device.
Another way of doing this is to use console tools hcitool and gatttool.
Scan:
sudo hcitool lescan
Connecting and getting services and descriptors:
sudo gatttool -b YOUR_MAC -I -t random> connect> primary> char-desc
In some cases BLE stack can glitch and you can turn on/off your bluetooth or run this command:
sudo hciconfig hci0 reset
Preparing to sniff data
To sniff data from our phone <-> band communication we will need to enable bluetooth log in dev settings. To do this you need to turn on developers settings on your android phone first.
Here is steps to do it:On Android 4.1 and lower, the Developer options screen is available by default. On Android 4.2 and higher, you must enable this screen as follows:
- Open the Settings app.
- (Only on Android 8.0 or higher) Select System.
- Scroll to the bottom and select About phone.
- Scroll to the bottom and tap Build number 7Â times.
- Return to the previous screen to find Developer options near the bottom.
Now open dev settings and find âEnable Bleutooth HCI snoop logâ and enable it. From this time all your Bluetooth communication will be logged. Then you will need to find file called btsnoop_hci.log (in my case (Android 7.0) it was in /mtklog/btlog/btsnoop_hci.log)
Authentication
So now we will need to do this steps to get some info about how authentication(pairing) works.
- Turn on Bluetooth and HCIÂ log.
- Pair your device to the Xiaomi Android App.
- Turn off bluetooth.
- Download your btsnoop_hci.log to your PC.
- Open it with Wireshark.
- Find First ATT protocol request that go to handle 0x0055
And you will see something like this:
This request is a first step of Auth processHere is Authentication steps:
Pairing deviceMain service UUID 0000fee1-0000â1000â8000â00805f9b34fbAuth Characteristic (Char) UUID 00000009â0000â3512â2118â0009af100700Notification descriptor (Des) handle 0x2902 (it same for all stuff)
- Setting on auth notifications (to get response) by sending 2 bytes request \x01\x00 to the Des.
- Send 16 bytes encryption key to the Char with command, appending to it 2 bytes \x01\x00 +Â KEY.
- Requesting random key from device with command by sending 2 bytes \x02\x00 to the Char.
- Getting random key from device response (last 16Â bytes).
- Encrypt this random number with our 16 bytes key and with AES/ECB/NoPadding use (from Crypto.Cipher import AES) and send it back to the Char (\x03\x00 + encoded data)
Authentication
- Requesting random key from device with command by sending 2 bytes \x02\x00 to the Char.
- Getting random key from device response (last 16Â bytes).
- Encrypt this random number with our 16 bytes key and with AES/ECB/NoPadding use (from Crypto.Cipher import AES) and send it back to the Char (\x03\x00 + encoded data)
Real Time Data
That was little more complicated then Auth process, because i didnât see that made a mistake in the process :) And because of this heart rate monitor was turning off after 15 sec.
Hardware service (HRDW) UUID 0000fee0â0000â1000â8000â00805f9b34fbHeart Monitor Service (HMS) UUID0000180d-0000â1000â8000â00805f9b34fbHeart Rate Measure Characteristic (HRM) UUID 00002a37â0000â1000â8000â00805f9b34fbHeart Monitor Control Characteristic (HMC) UUID 00002a39â0000â1000â8000â00805f9b34fbSensor Characteristic (SENS) UUID00000001â0000â3512â2118â0009af100700Notification descriptor (DES) handle 0x2902 (it same for all stuff)
- Turn off current hear monitor measurement.Sent request to HMC \x15\x02\x00 for one-shot measurements.Sent request to HMC \x15\x01\x00 for continous measurements.
- Enabling Gyroscope and Heart raw data by sending command to SENS \x01\x03\x19
- Enabling notification for HRM writing request to DESÂ \x01\x00
- Start continuous heart measurements by sending request to HMC \x15\x01\x01
- Sending command to SENS \x02 (donât know why this need)
- Then while getting notifications every 12 seconds we need to send \x16 ping to the HCM
Parsing data
Thatâs not very interesting part, cause basically you need to find out how to unpack data that come from device.
Some part of it can be parsed from logs, and some not.
Here is response from device with current time
Finding the right packets and encoding can take some time. In my case i tried to find similar bytes occurrences in packets next to each other, some repeating in packet.
Raw heart: 02102d8c348c448c458c3d8c428c488c 16Raw heart: 0218468c418c3d8c468c3f8c398c418c 16Realtime heart: 93Raw heart: 0220408c448c3f8c428c498c3c8c3d8c 16Raw heart: 02283d8c398c488c3e8c468c488c328c 16Realtime heart: 99Raw heart: 0230438c408c378c3a8c318c458c388c 16Realtime heart: 102Raw heart: 02404f8c408c458c428c4d8c558c4d8c 16Raw heart: 02483e8c3b8c3f8c348c398c318c428c 16Realtime heart: 98Raw heart: 02504c8c428c5e8c4f8c588c498c558c 16Raw heart: 0258478c458c3c8c4e8c3f8c468c4d8c 16Realtime heart: 100Raw heart: 0260518c4d8c4f8c4b8c4f8c528c458c 16Raw heart: 0268408c3f8c538c4d8c408c548c598c 16Realtime heart: 102Raw heart: 0278418c508c4e8c548c588c468c498c 16Raw heart: 0280368c328c2e8c3c8c338c308c3f8c 16Realtime heart: 101
He we can see clear pattern repeating 368c 328c 2e8c 3c8c 338c 308c 3f8c and the packet is 16 bytes length. So if we unpack this with 2 bytes unsigned short then we get 7 raw measurements of the heart sensor. Also we see that second byte just iterating, and i think itâs just time difference between measurements(i mean between responses)
Raw gyro: 01de49ffd9ff3c004cffd8ff3b004dffdcff4400Raw gyro: 01df4cffd6ff44004dffd8ff40004cffd1ff4700Raw gyro: 02e1103231323d3274328e329632af32c732cf32Raw gyro: 01e34fffd7ff56004bffc7ff590049ffccff4c00Raw gyro: 01e443ffccff43004effcdff40005bffd4ff4c00Raw gyro: 01e558ffc9ff5f005effbfff66005fffb0ff5900Raw gyro: 01e64cffacff60005cffa7ff410066ffc9ff4600Raw gyro: 01e760ffdcff4b0051ffe4ff4f0034ffdeff5300Raw gyro: 02e903365c36813663361036543688374139fe3aRaw gyro: 01eb4bffc3ff50004fffc1ff430047ffbbff4100Raw gyro: 01ec3effb2ff3c0050ffbfff560047ffccff7300Raw gyro: 01ed4fffe0ff78005cffebff8e0056fff6ff8300Raw gyro: 01ee7efffbffa1008bff0f00bc00b1ff1900b800Raw gyro: 01ef9bff0c00d10095fff3ffd600b7ff0800df00Raw gyro: 02f12445314600479e473348aa481c499749244aRaw gyro: 01f3c3ff1600fe00beff1800f200a6ff0800e700Raw gyro: 01f4a9fff8ffd300a7fff3ffd700a9fff1ffdf00Raw gyro: 01f5b1fff8ffe800b4fff1fff700acfffcffef00Raw gyro: 01f67ffff7ffc0006bfff4ffb00078ffe9ffb600Raw gyro: 01f786ffecffc0006ffff0ffbc0060fff1ffc000Raw gyro: 02f9ca4cbb4c784c964ca84c784c854c444c1b4cRaw gyro: 01fb7cff0f00bb007eff2700ae0083ff30009800Raw gyro: 01fc79ff1800b00076ff0f00bc0068ff0900d900Raw gyro: 01fd78ff07000c01f6fffbff19011c000b00f600Raw gyro: 01fe4b001100d30054000700c3004300efffeb00Raw gyro: 01ff1f00d0ff1701fbffe8ff1b01e3ffffff1101Raw gyro: 0201214b014bec4ad04aba4acb4abe4aba4abd4aRaw gyro: 0103efffecfffc00e3fff3fff300defff3fffc00Raw gyro: 0104e3fff0fff400e6ffefff0301dbffe9ff0c01Raw gyro: 0105e3fff0ff0301e6ffe6fffc00dcffecfffc00Raw gyro: 0106dffff0fff700dbffeefff600d6fff0fff400Raw gyro: 0107dfffecffff00e1fff0ff0301defff3fffc00
As for Gyroscope it was a bit harder. But my thoughts was that it should be packed in the similar way as heart data, but in this case we have 3 measurements for each gyro axis which should be signed and packet length is 20 bytes. So 12 x,y,z measurement will not cover all package, but 3 will, leaving first 2 bytes (the same as in previous packet). So i tried this and it works :)
The code
Code you can find on my github repo as always, with example of use. Itâs pretty simple, so donât need to comment it in this article.
Support
If you like my articles, you can always support me with some beer-money https://paypal.me/creotiv
Read my other fresh articles
- Feature extraction and similar image search with OpenCV for newbies
- Tutorial: Making Road Traffic Counting App based on Computer Vision and OpenCV
How i hacked Xiaomi MiBand 2 to control it from Linux was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.