Polar H7 Bluetooth LE Heart Rate Sensor on Ubuntu 14.04

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 hcitool and gatttool.

Scanning for the Polar H7

$ sudo hcitool -i hci1 lescan  
LE Scan ...  
00:22:D0:33:1E:0F (unknown)  

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

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 gatttool connection.

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), ServicesCharacteristics, 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:

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.

Battery Service

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-desc and 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.

GATT Characteristics

[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 website were updated to reflect new locations.


comments powered by Disqus