How to connect the Raspberry Pi to a Bluetooth heart rate monitor

In addition to your Raspberry Pi, you will need the following hardware:

Next, download, compile and install the latest ‘BlueZ’ on your Raspberry Pi. BlueZ is the Bluetooth stack for Linux, and it works with Raspbian. Plug your bluetooth dongle into your Pi and the following commands will install BlueZ:


This is a companion discussion topic for the original entry at http://reprage.com/post/how-to-connect-the-raspberry-pi-to-a-bluetooth-heart-rate-monitor

Any suggestions for using Python to call the H7 heart rate monitor? I have my exercise cycle sensors running on the Pi with a Python Program, and I’d like to add heart rate data collection the that Python program…

Looks like pybluez should get you connected to the H7. The code above and references should give you a rough idea of what services and characteristics you need to listen for.

BT newbie. Can one raspberry Pi receive and log from say 15 h7 devices? Like a team scenario?
How would you tackle that one?

I haven’t tested it, but the underlying gatt API should call onPeriphDiscovered for each of the 15 h7 devices, when detected by the Pi. Each of the 15 devices will have their own unique peripheral ID (a uuid).

When you log the data, keep track of the peripheral ID and use that to identify the heart rate measurement came from which of the 15 h7 devices: i.e.

periphID, HR
1542be93-bbf5-4b8c-ab38-c53f245a8f11, 88
63e1f30f-0845-41ee-972c-e37eeff17da9, 92

You will probably need some sort of naming / registration system for turning the periphID into something meaningful like ‘playerA’ or ‘Bob’.

Nice, i could probably number them, and tag each H7 #1, #2, #3… then add names on a user interface.
Does the pi poll the H7 or do they report? If the load gets too high or traffic gets too high for pi3, we could offload into two units… but i dont think 15 devices is too much traffic.

Thanks. now i need to find a dev, this is out of my league .

I believe the H7 will report the heart rate every second. So the traffic is fairly low, the biggest constraint will probably be range. I’m not sure how far you will get from the Pi before the H7 disconnects. I suspect the range will reduce for each Polar H7 connected to the Pi.

You are correct. My experience is in the wisp industry, so i might be able to work a better antena for a BT4 receiver. Im thinking placing the receiver on top of the athletes in a room might work better. Less body mass to go thru. am also researching other heart rate bands from less known vendors , and see if they can provide a dev kit or sdk.

My RPi3 finds my Polar H7 HRM as in your example, but from there I am not sure I did all the rest correctly.

I ran the go install and I did get the WeatherMachine2-hrm executable in my /bin folder. When I execute it, there is no output to the terminal. Looking at Weathermachine2-hrm.log I see INFO: SCANNING and some DATA: […], but no the output I would have expected.

What am I doing wrong ?

Unfortunately, this code predates the RPi3 - It was developed with a RPi2 and an external USB bluetooth dongle. The bluetooth library that this was built ontop of came from paypal – https://github.com/paypal/gatt – it seems to be largely abandoned these days. It also was extremely fussy with bluez.

More recently I was playing around with Bluetooth on the Intel Edison (using the internal radio) and found this library – https://github.com/muka/go-bluetooth – to be more reliable and portable across devices. Plus it works in conjunction with bluez, rather than fight it.

This little snippet below is how I was pulling data off the heart rate monitor:

func pollHeartRateMonitor(hr chan uint16, halt chan bool) {
// Connect bluetooth.
hciconfig := linux.HCIConfig{}
_, err := hciconfig.Up()
if err != nil {
	log.Printf("Unable to connect %s", err)
	return
}

// Bluetooth cleanup function.
defer func() {
	api.Exit()

	_, err = hciconfig.Down()
	if err != nil {
		log.Printf("Unable to disconnect %s", err)
		return
	}

	log.Printf("HRM stopped.")
}()

// Give the hardware a second to warmup.
time.Sleep(time.Second)

// See if the device is known first.
d, err := api.GetDeviceByAddress("0C:F3:EE:AA:B1:F7")
if err != nil {
	log.Printf("Unable to get device %s", err)
	return
}

// Unable to find the device, try discovering it for 10 seconds.
if d == nil {
	log.Printf("Starting discovery")
	err = api.StartDiscovery()
	if err != nil {
		log.Printf("Unable to start discovery %s", err)
	}

	api.On("discovery", emitter.NewCallback(func(ev emitter.Event) {
		discoveryEvent := ev.GetData().(api.DiscoveredDeviceEvent)
		dev := discoveryEvent.Device

		if dev == nil {
			log.Printf("Device removed!")
			return
		}

		log.Printf("Found %v", dev)
	}))

	time.Sleep(10 * time.Second)
	log.Printf("Stopping discovery")
	api.StopDiscovery()

	d, err = api.GetDeviceByAddress("0C:F3:EE:AA:B1:F7")
	if err != nil {
		log.Printf("Unable to get device %s", err)
		return
	}
}


log.Printf("Connecting to device %v", d.Properties)
err = d.Connect()
if err != nil {
	log.Printf("Unable to connect to device %s", err)
	return
}

// Discover the bluetooth device characteristics.
char := getCharacteristic(d, "2A37")
if char == nil {
	log.Printf("waiting while characteristics are discovered")
	time.Sleep(15 * time.Second)
	char = getCharacteristic(d, "2A37")
}

hrChannel, err := char.Register()
if err != nil {
	log.Printf("Unable to register to characteristic %s", err)
	return
}

err = char.StartNotify()
if err != nil {
	log.Printf("StartNotify error %v", err)
	return
}
log.Printf("Characteristic registered %v", char)

for e := range hrChannel {
	if e == nil {
		return
	}

	select {
	case <-halt:
		log.Printf("Stopping HRM")
		char.StopNotify()
		return
	default:
		// Keep polling.
	}

	switch v := e.Body[1].(type) {
		case map[string]dbus.Variant:
			if val, ok := v["Value"]; ok {
				heartRate := binary.LittleEndian.Uint16(append([]byte(val.Value().([]byte)[1:2]), []byte{0}...))
				hr <- heartRate
			}
		default:
			log.Printf("Unable to determine type %v", v)
	}
}

}