Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HeartRate notify #53

Closed
jorismathijssen opened this issue May 31, 2015 · 18 comments
Closed

HeartRate notify #53

jorismathijssen opened this issue May 31, 2015 · 18 comments

Comments

@jorismathijssen
Copy link

@jorismathijssen jorismathijssen commented May 31, 2015

Hi there, first of all thanks for reading this!

Currently i am working on a heart rate monitor in python with the polar H7 and i'm getting stuck with the notify part of BLE heart rate.

import struct
import btle


class MyDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)

    def handleNotification(self, cHandle, data):
        print(data)


if __name__ == '__main__':
    heartrate_uuid = btle.UUID(0x2a38)

p = btle.Peripheral("00:22:D0:2B:F8:EC")
p.setDelegate(MyDelegate())

print("Connected")

try:
    print("Setting Characteristics")
    ch = p.getCharacteristics(uuid=heartrate_uuid)[0]
    print("Setting Done, writing now")
    ch.write(struct.pack('<bb', 0x01, 0x00))
    print("writing Done, looping now")
    while True:
        if p.waitForNotifications(1.0):
            print("Notification trigger")
            continue
    print("Waiting")
finally:
    p.disconnect()

Im not sure where i go wrong but i guess i dont have the right setup_data (from the example)

Can someone get me back on the right track?

@markrages

This comment has been minimized.

Copy link
Contributor

@markrages markrages commented Jun 29, 2015

Here is a working heart rate example.

You will obviously need to change the address.

from btle import Peripheral, ADDR_TYPE_RANDOM, AssignedNumbers

import time

class HRM(Peripheral):
    def __init__(self, addr):
        Peripheral.__init__(self, addr, addrType=ADDR_TYPE_RANDOM)

if __name__=="__main__":
    cccid = AssignedNumbers.client_characteristic_configuration
    hrmid = AssignedNumbers.heart_rate
    hrmmid = AssignedNumbers.heart_rate_measurement

    hrm = None
    try:
        hrm = HRM('cb:d7:a0:40:c4:01')

        service, = [s for s in hrm.getServices() if s.uuid==hrmid]
        ccc, = service.getCharacteristics(forUUID=str(hrmmid))

        if 0: # This doesn't work
            ccc.write('\1\0')

        else:
            desc = hrm.getDescriptors(service.hndStart,
                                      service.hndEnd)
            d, = [d for d in desc if d.uuid==cccid]

            hrm.writeCharacteristic(d.handle, '\1\0')

        t0=time.time()
        def print_hr(cHandle, data):
            bpm = ord(data[1])
            print bpm,"%.2f"%(time.time()-t0)
        hrm.delegate.handleNotification = print_hr

        for x in range(10):
            hrm.waitForNotifications(3.)

    finally:
        if hrm:
            hrm.disconnect()
@jsulmer

This comment has been minimized.

Copy link

@jsulmer jsulmer commented Dec 18, 2015

@markrages
I've tried to get the HRM example working. However I couldn't connect my polar H7. Did I missed something when I just copy paste the script from above into a new .py file?

@jorismathijssen

This comment has been minimized.

Copy link
Author

@jorismathijssen jorismathijssen commented Dec 18, 2015

Did you try the right Address ? is it available ? try to connect with a phone or a tool on pc

@jorismathijssen

This comment has been minimized.

Copy link
Author

@jorismathijssen jorismathijssen commented Dec 18, 2015

Maybe this will help you out

import struct
import btle
import sys


heartrate_uuid = btle.UUID(0x2a37)


class heartMonitor:
def __init__(self, mac):
    try:
        self.p = btle.Peripheral(mac)
        self.p.setDelegate(heartDelegate())
    except:
        self.p = 0
        print "Not connected"

def startMonitor(self):
    try:
        self.p.writeCharacteristic(0x12, struct.pack('<bb', 0x01, 0x00), False)
        self.p.writeCharacteristic(0x11, '\x04', False)
    except:
        e = sys.exc_info()[0]
        print("HeartMonitor Error: %s" % e)
        try:
            self.p.disconnect()
        except:
            return 0

def getHeartbeat(self):
    try:
        self.p.waitForNotifications(1.0)
        return self.p.delegate.getlastbeat()
    except:
        return 0

def stopMonitor(self):
    self.p.writeCharacteristic(0x11, '\x00', False)


class heartDelegate(btle.DefaultDelegate):
message = 0

def __init__(self):
    btle.DefaultDelegate.__init__(self)

def handleNotification(self, cHandle, data):
    if(data[0] == '\x14'):
        self.message = "Connection Lost"
    if(data[0] == '\x16'):
        self.message = str(struct.unpack("B", data[1])[0])
    if(data[0] == '\x06'):
        self.message = "Booting"

def getlastbeat(self):
    return self.message
@jsulmer

This comment has been minimized.

Copy link

@jsulmer jsulmer commented Dec 18, 2015

I'm able to connect to the device via gatttool -b and start the heartrate notification handler. I will try the code and see if this works.

@jsulmer

This comment has been minimized.

Copy link

@jsulmer jsulmer commented Dec 21, 2015

I'm totally new to python, stuggeling with indentation and so on. Need to start over from scratch and first learn the basics. Thanks anyhow for your help.

@jorismathijssen

This comment has been minimized.

Copy link
Author

@jorismathijssen jorismathijssen commented Dec 21, 2015

Indentation is a bit of a pain, try to work in a nice editor will help you! (sublime is a good one). If you need help feel free to contact me!

@karthikbnd

This comment has been minimized.

Copy link

@karthikbnd karthikbnd commented Apr 1, 2016

Hai
I need to get the heartrate measurement, with uuid 0x2A37 and is in notify state. help needed

@jorismathijssen

This comment has been minimized.

Copy link
Author

@jorismathijssen jorismathijssen commented Apr 1, 2016

Did you try my code above?

@karthikbnd

This comment has been minimized.

Copy link

@karthikbnd karthikbnd commented Apr 1, 2016

yes
but where to specify the mac address of the HRM F5:F1:17:A0:21:5A

and there is an intendation errror at
class heartMonitor:
def init(self, mac):
try:

Can u please tell me the exact code working

@karthikbnd

This comment has been minimized.

Copy link

@karthikbnd karthikbnd commented Apr 1, 2016

I tried this code

#!/usr/bin/python
import struct
from bluepy.bluepy import btle
import sys

heartrate_uuid = btle.UUID(0x2a37)
mac = "F5:F1:17:A0:21:5A"

class heartMonitor:
def init(self):
try:
self.p = btle.Peripheral("F5:F1:17:A0:21:5A")
self.p.setDelegate(heartDelegate())
except:
self.p = 0
print "Not connected"

def startMonitor(self):
try:
self.p.writeCharacteristic(0x12, struct.pack('<bb', 0x01, 0x00), False)
self.p.writeCharacteristic(0x11, '\x04', False)
except:
e = sys.exc_info()[0]
print("HeartMonitor Error: %s" % e)
try:
self.p.disconnect()
except:
return 0

def getHeartbeat(self):
try:
self.p.waitForNotifications(1.0)
return self.p.delegate.getlastbeat()
except:
return 0

def stopMonitor(self):
self.p.writeCharacteristic(0x11, '\x00', False)

class heartDelegate(btle.DefaultDelegate):
message = 0

def init(self):
btle.DefaultDelegate.init(self)

def handleNotification(self, cHandle, data):
if(data[0] == '\x14'):
self.message = "Connection Lost"
if(data[0] == '\x16'):
self.message = str(struct.unpack("B", data[1])[0])
if(data[0] == '\x06'):
self.message = "Booting"

def getlastbeat(self):
return self.message

when i execute nothing is printed
hrm.txt

@markrages

This comment has been minimized.

Copy link
Contributor

@markrages markrages commented Apr 9, 2016

You may wish to use the higher-level API which I posted at
https://github.com/markrages/ble

Have a look at the example to see if you would prefer its API. It is
basically as different interface for the same functionality.

Regards,
Mark
markrages@gmail

On Fri, Apr 1, 2016 at 4:54 AM, Karthik Bandi notifications@github.com
wrote:

I tried this code

#!/usr/bin/python
import struct
from bluepy.bluepy import btle
import sys

heartrate_uuid = btle.UUID(0x2a37)
mac = "F5:F1:17:A0:21:5A"

class heartMonitor:
def init(self, mac):

try:
self.p = btle.Peripheral(mac)
self.p.setDelegate(heartDelegate())
except:
self.p = 0
print "Not connected"

def startMonitor(self):
try:
self.p.writeCharacteristic(0x12, struct.pack('<bb', 0x01, 0x00), False)
self.p.writeCharacteristic(0x11, '\x04', False)
except:
e = sys.exc_info()[0]
print("HeartMonitor Error: %s" % e)
try:
self.p.disconnect()
except:
return 0

def getHeartbeat(self):
try:
self.p.waitForNotifications(1.0)
return self.p.delegate.getlastbeat()
except:
return 0

def stopMonitor(self):
self.p.writeCharacteristic(0x11, '\x00', False)

class heartDelegate(btle.DefaultDelegate):
message = 0

def init(self):
btle.DefaultDelegate.init(self)

def handleNotification(self, cHandle, data):
if(data[0] == '\x14'):
self.message = "Connection Lost"
if(data[0] == '\x16'):
self.message = str(struct.unpack("B", data[1])[0])
if(data[0] == '\x06'):
self.message = "Booting"

def getlastbeat(self):
return self.message


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#53 (comment)

Regards,
Mark
markrages@gmail

@IanHarvey

This comment has been minimized.

Copy link
Owner

@IanHarvey IanHarvey commented Apr 14, 2016

The Python code is quite hard to follow, because it's lost its indentation. You can post code samples by putting:
```python
before it, and
```
afterwards.

It seems you're defining a HeartMonitor class, but never actually instantiating it. The code for this might look something like ...

hrm = HeartMonitor()
hrm.startMonitor()
while True:
    hrm.getHeartBeat()

Personally, I would also avoid the "Pokemon" programming style i.e. try: except: clauses around everything. Python will turn pretty much any sort of programming error (e.g. badly-spelled function names, wrong parameters, bad types) into an exception and you really don't want to catch 'em all, it makes debugging simple typos really hard.

@Jeffrey-Hall

This comment has been minimized.

Copy link

@Jeffrey-Hall Jeffrey-Hall commented Aug 12, 2016

Hi,

Is it universally true that for a given characteristic handle n, the descriptor notification can be set by writing a "1" to the next higher handle, n + 1? I'm trying to get notifications working when connecting to a BlueRadio BLE "modem". I can write data to the modem and it shows up. But I can't get seem to get notifications working to read data sent by the modem.

Is there any other way to get the descriptor handle and enable/disable notifications? I seem to be able to write to the descriptor handle, but my delegate never gets called.

Thanks
-Jeff-

@IanHarvey

This comment has been minimized.

Copy link
Owner

@IanHarvey IanHarvey commented Jan 30, 2017

Is there any other way to get the descriptor handle and enable/disable notifications?

Services and characteristics now have a getDescriptors() method (commit 5c107d1 and later). Code to use them looks something like this (see pull request #89):

   char = peripheral.getCharacteristics(uuid=your_uuid_here)[0]
   ccc_desc = char.getDescriptors(forUUID=0x2902)[0]
   ccc_desc.write(b"\x01")

The sensortag.py code now (commit 9945d88) uses this to enable notifications on the sensortag's "keypress" service.

@IanHarvey IanHarvey closed this Jan 30, 2017
@0xRoM 0xRoM mentioned this issue Feb 13, 2019
@graphl

This comment has been minimized.

Copy link

@graphl graphl commented Sep 10, 2019

Hi,

Is it universally true that for a given characteristic handle n, the descriptor notification can be set by writing a "1" to the next higher handle, n + 1? I'm trying to get notifications working when connecting to a BlueRadio BLE "modem". I can write data to the modem and it shows up. But I can't get seem to get notifications working to read data sent by the modem.

Is there any other way to get the descriptor handle and enable/disable notifications? I seem to be able to write to the descriptor handle, but my delegate never gets called.

Thanks
-Jeff-

The problem has been solved?

@shining

This comment has been minimized.

Copy link

@shining shining commented Sep 22, 2019

Hello,

Thanks to this post : https://blog.alikhalil.tech/2014/11/polar-h7-bluetooth-le-heart-rate-sensor-on-ubuntu-14-04/ , I was able to get the data from a polar h7 to a debian laptop.
However it stops after 30 seconds.
Then I tried with bluepy, adapting the sample code above.
I also tried with markrages API, using blueby or dbus backends.
In all cases it stops after 30 seconds.

The problem can be seen with btmon :

> ACL Data RX: Handle 3585 flags 0x02 dlen 16                                                   #304 [hci0] 737.782147
      LE L2CAP: Connection Parameter Update Request (0x12) ident 123 len 8
        Min interval: 250
        Max interval: 400
        Slave latency: 0
        Timeout multiplier: 600
< ACL Data TX: Handle 3585 flags 0x00 dlen 10                                                   #305 [hci0] 737.782283
      LE L2CAP: Connection Parameter Update Response (0x13) ident 123 len 2
        Result: Connection Parameters rejected (0x0001)
> HCI Event: Number of Completed Packets (0x13) plen 5                                          #306 [hci0] 737.832341
        Num handles: 1
        Handle: 3585
        Count: 1
> HCI Event: Disconnect Complete (0x05) plen 4                                                  #307 [hci0] 737.984340
        Status: Success (0x00)
        Handle: 3585
        Reason: Unacceptable Connection Parameters (0x3b)
@ MGMT Event: Device Disconnected (0x000c) plen 8                                           {0x0003} [hci0] 737.984425
        LE Address: 00:22:D0:EB:D2:5F (Polar Electro Oy)
        Reason: Unspecified (0x00)

A workaround is to run the following as root in the first 30 seconds of the connection : hcitool lecup --handle 3585 --min 250 --max 400 --latency 0 --timeout 600

But I don't understand who is rejecting the Connection Parameter Update and why.

I monitored what happens between the polar h7 and an android phone, with an app using polar SDK. I see exactly the same Connection Parameter Update Request, but it's accepted, and the phone then sends a LE connection update with the requested params and all goes well.

I have tried changing /sys/kernel/debug/bluetooth/hci0/conn_min_interval & co but it does not seem to have any impacts, neither on the params used for the initial connection, nor on the Connection Parameter Update Request which is always rejected.

So how could avoid manually running hictool lecup ? Do you have any other workarounds ?

@kenaycock

This comment has been minimized.

Copy link

@kenaycock kenaycock commented Oct 6, 2019

@shining I am similarly working on using bluepy to log data from a Cycling Speed and Cadence (CSC) sensor and am having the same problem, disconnects after ~30 seconds (actually ~38sec). hcidump indicates the reason is Unacceptable Connection Parameters:

...........................................
2019-10-06 15:14:02.498711 > ACL data: handle 35 flags 0x02 dlen 18
    ATT: Handle notify (0x1b)
      handle 0x0018
      value 0x03 0x1c 0xd8 0x06 0x00 0x08 0x5e 0x71 0x3d 0xc3 0x07 
2019-10-06 15:14:03.505740 > ACL data: handle 35 flags 0x02 dlen 18
    ATT: Handle notify (0x1b)
      handle 0x0018
      value 0x03 0x1f 0xd8 0x06 0x00 0x34 0x62 0x71 0x3d 0xc3 0x07 
2019-10-06 15:14:04.049367 > HCI Event: Disconn Complete (0x05) plen 4
    *status 0x00 handle 35 reason 0x3b*
    *Reason: Unacceptable Connection Parameters*

Anyway, I too played around changing parameters in /sys/kernel/debug/bluetooth/hci0/* to no avail, but your workaround using hcitool lecup --handle 3585 --min 250 --max 400 --latency 0 --timeout 600 works!

All: any additional insight on what's going wrong and how to fix the connection parameters when initializing the connection in bluepy? @shining, perhaps we should open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
9 participants
You can’t perform that action at this time.