I recently picked up the Polar H7 Heart Rate Sensor (Bluetooth Low Energy). The long term goal is to connect up the sensor to my HTPC running XBMC so that I can see my heart rate on the screen while I work out. I usually work out to music playing on the HTPC or watching P90X videos. So, it’d be nice to be able to see the heart rate information real time as well as record it in a file/db for historic purposes.
Now, I haven’t really played with low level communication with Bluetooth devices. It seems that Bluetooth Low Energy (BLE) is a lot different from Bluetooth Classic, but for me it didn’t matter much since it’s the first time I’m messing around with Bluetooth in general.
The first challenge in connecting to the Polar H7 turned out to be a lack of a BLE compatible adapter. My laptop has a Broadcom BCM2070 chip which only provides Bluetooth 3.0. It turns out that BLE is only available with 4.0+. So, I needed to purchase a USB dongle. Once I had that it was time to figure out how to connect to it. I thought it’d be a lot easier than it actually was.
Long story short… it took me a few days of digging around on Google Search to find the information I needed. I was surprised at how little information there really was for connecting to and communicating with BLE HRM devices and specifically the Polar H7. Here’s how I got the initial connection established to be able to get some data from the device on
Ubuntu 14.04 using
Scanning for the Polar H7
$ sudo hcitool -i hci1 lescan LE Scan ... 00:22:D0:33:1E:0F (unknown) 00:22:D0:33:1E:0F
This will run a BLE scan and provide the MAC address of the Polar H7. The scan will run continously, so you’ll have to
CTRL+C to stop. The MAC address is required to establish a connection to it.
Connecting to the Polar H7
The next thing is to connect to the device, and for that I used
gatttool in interactive mode. My USB Bluetooth 4.0 dongle shows up as
hci1 on my system. It might be different for you. Run
hcitool dev to find out.
$ sudo gatttool -i hci1 -b 00:22:D0:33:1E:0F -I [ ][00:22:D0:33:1E:0F][LE]> connect [CON][00:22:D0:33:1E:0F][LE]>
If you want to jump forward to the reading of heart rate data skip directly to it. I’ll now cover a bit of information on what data I was able to gather from the
Services and Characteristics
If you want to really familiarize yourself with the BLE capabilities touched upon here you need to know Generic Attribute Profile (GATT), Services, Characteristics, and Client Characteristic Configuration. I have to admit that I’ve barely scratched the surface on this. There’s probably a lot more to know.
To get a list of all services presented by the device.
[CON][00:22:D0:33:1E:0F][LE]> primary attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb attr handle: 0x000c, end grp handle: 0x000e uuid: 00001801-0000-1000-8000-00805f9b34fb attr handle: 0x000f, end grp handle: 0x0014 uuid: 0000180d-0000-1000-8000-00805f9b34fb attr handle: 0x0015, end grp handle: 0x0023 uuid: 0000180a-0000-1000-8000-00805f9b34fb attr handle: 0x0024, end grp handle: 0x0026 uuid: 0000180f-0000-1000-8000-00805f9b34fb attr handle: 0x0027, end grp handle: 0xffff uuid: 6217ff49-ac7b-547e-eecf-016a06970ba9
The first 8 bytes of the UUID value indicate the service. The key ones here are:
- 0x180d - Heart Rate (org.bluetooth.service.heart_rate)
- 0x180f - Battery Service (org.bluetooth.service.battery_service)
My end goal for this blog entry is to demonstrate Heart Rate data readings. So, I’ll save that for last. Let’s start at the Battery Service.
Going forward note that all values returned are in HEX format.
Let’s focus on the below line
attr handle: 0x0024, end grp handle: 0x0026 uuid: 0000180f-0000-1000-8000-00805f9b34fb
Services provide characteristics which provide data. Here’s how we read characteristics from the Battery Service using the
char-read-hnd commands. We need the
attr handle and
end grp handle values here so note those.
[CON][00:22:D0:33:1E:0F][LE]> char-desc 0x0024 0x0026 handle: 0x0024, uuid: 2800 handle: 0x0025, uuid: 2803 handle: 0x0026, uuid: 2a19
The UUID of interest is
0x2a19. Note the handle i.e.
0x0026. This will provide the current battery level.
[CON][00:22:D0:33:1E:0F][LE]> char-read-hnd 0x0026 Characteristic value/descriptor: 51
The value is displayed in HEX. Therefore the value of 51 is actually 81%.
Heart Rate Service
Now, we get to the heart of the matter (pun intended)… reading the heart rate information. Let’s look at the Heart Rate service.
attr handle: 0x000f, end grp handle: 0x0014 uuid: 0000180d-0000-1000-8000-00805f9b34fb [CON][00:22:D0:33:1E:0F][LE]> char-desc 0x000f 0x0014 handle: 0x000f, uuid: 2800 handle: 0x0010, uuid: 2803 handle: 0x0011, uuid: 2a37 handle: 0x0012, uuid: 2902 handle: 0x0013, uuid: 2803
This part was tricky to figure out. Here we’re going to be dealing with NOTIFY to get the real time heart rate data. See the Heart Rate Service for more details. Notify has to be turned on by changing the Characteristic Configuration at handle
0x0012 i.e. UUID
0x2902. The data returned is from handle
0x0011 i.e. UUID
0x2a37 which is the characteristic that provides Heart Rate Measurement.
[CON][00:22:D0:33:1E:0F][LE]> char-write-req 0x0012 0100 [CON][00:22:D0:33:1E:0F][LE]> Characteristic value was written successfully Notification handle = 0x0011 value: 06 61 Notification handle = 0x0011 value: 16 62 70 02 71 02 Notification handle = 0x0011 value: 16 60 75 02 84 02 Notification handle = 0x0011 value: 16 5f 8f 02 Notification handle = 0x0011 value: 16 5d a2 02 9d 02 Notification handle = 0x0011 value: 16 5d 93 02 Notification handle = 0x0011 value: 16 5c 92 02 99 02
The above will keep going on. I was able to get over 5000 readings during a test session. To turn off notify…
[CON][00:22:D0:33:1E:0F][LE]> char-write-req 0x0012 0000 [CON][00:22:D0:33:1E:0F][LE]> Characteristic value was written successfully
I came across the Polar H7 heart rate packet format this article. Code source: MyTracks for Android
* Polar Bluetooth Wearlink packet example; * Hdr Len Chk Seq Status HeartRate RRInterval_16-bits * FE 08 F7 06 F1 48 03 64 * where; * Hdr always = 254 (0xFE), * Chk = 255 - Len * Seq range 0 to 15 * Status = Upper nibble may be battery voltage * bit 0 is Beat Detection flag.
So far, I can’t relate the packet data format to the readings I’m seeing from the device. After fiddling around with the data received I think I figured it out. The heart rate is the second octet.
06 61 => 97 16 62 70 02 71 02 => 98 16 60 75 02 84 02 => 96 16 5f 8f 02 => 95 16 5d a2 02 9d 02 => 93 16 5d 93 02 => 93 16 5c 92 02 99 02 => 92
It looks like the rate of messages is about 1 per second. There you have it. Real time heart rate data from the Polar H7.
What’s next? XBMC add-ons are written in Python, and I’ll need to be able to read the heart rate data in to the add-on script to be able to display it on screen. From what I can tell Python capabilities with Bluetooth LE are limited and appear to be in its infancy. The best option I’ve seen is bluepy. It works, but I don’t see it as ideal. A binary has to be compiled from source for it to work.
- April 2019 - All links pointing to pages on the bluetooth.com website were updated to reflect new locations.