peplin / pygatt

Python wrapper for gatttool (a deprecated tool from BlueZ) and the BGAPI for accessing Bluetooth LE Devices
Other
527 stars 185 forks source link

Writing to Descriptor #70

Closed andyboeh closed 5 years ago

andyboeh commented 7 years ago

I just came over pygatt while trying to connect to a cheap Pulse Oximeter (BerryMed). This one requires to write to the Client Character Config Descriptor to enable the streaming of data packets.

Since the CCCD is not included during characteristics discovery, pygatt doesn't let me write to it using its UUID. Any suggestions how I can write to this descriptor using pygatt?

EDIT: It looks like some work on this has been done on the branch "gattool-fix"!?

BhargavaRamM commented 7 years ago

@andyboeh did you try writing to the descriptor handle? You can get the handle from UUID and can use pygatt's char_write_handle to start getting notifications from the sensor.

andyboeh commented 7 years ago

Unfortunately, I get the same error message when doing device.get_handle(UUID): pygatt.exceptions.BLEError: No characteristic found matching 00002902-0000-1000-8000-00805f9b34fb

It checks internally if the UUID is available as a characteristic (which it isn't!) and thus fails.

e27182 commented 7 years ago

I was investigating similar thing - write to CCCD to enable notifications. But when I enabled DEBUG log level I found that library automatically enables notifications for all properties that support it. So, I'm good with it now. But, hopefully, my little investigation will give you some clues of how to access CCCDs manually (I did not tested it on a pygatt myself).

So, first of all I used gatttool to investigate how to enable notifications there. (Also inserted my comments between calls, I have doubts about 100% correctness, so if you spot any misleading info, please let me know):

$ gatttool -I # connect # primary ... attr handle: 0x002e, end grp handle: 0x0032 uuid: 0000180f-0000-1000-8000-00805f9b34fb ...

0x180f is a Battery Service

# characteristics 0x002e 0x0032 handle: 0x002f, char properties: 0x12, char value handle: 0x0030, uuid: 00002a19-0000-1000-8000-00805f9b34fb

0x2a19 is a Battery Level Characteristic

# char-desc 0x0031 0x0032 handle: 0x0031, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x0032, uuid: 00002908-0000-1000-8000-00805f9b34fb

0x2902 is a Client Characteristic Configuration Descriptor for service 0x180f

# char-write-req 0x0031 0100 Characteristic value was written successfully

0x0100 enables notification, it will be written to handle 0x0031 of CCCD 0x2902 of service 0x180f

.............. Notification handle = 0x0030 value: 5e

and after battery level changed you receive notification for "char value handle" 0x0030

So, basically, to do the same with pygatt you could try to get handle number with gatttool first as pygatt does not support char-desc command now, then use char_write_handle as suggested by @BhargavaRamM . Something like (not tested): adapter.char_write_handle(0x0031, bytearray([01 00]))

BhargavaRamM commented 7 years ago

@e27182 The issue here is that pygatt is not discovering CCCD as a characteristic. If you want to get the handle for CCCD, you have to check the handle value through gatttool using the above commands you used. I tried to find the handle value for CCCD of my BLE device using pygatt and it always returned characteristic not found error. Hence, pygatt was unable to write to the handle. I am not sure why this is happening with pygatt. Maybe @peplin can give us an answer.

e27182 commented 7 years ago

@BhargavaRamM , yep and the reason is here:

self.sendline('characteristics')

this command returns only characteristics for specified service. To retrieve descriptor for specified characteristic 'char-desc' command should be used with handler or range of handlers for the characteristic you are interested in. Sadly, it is not supported by pygatt now. And this branch "gattool-fix" actually adding support of it, but now it seems too old..

peplin commented 7 years ago

A pull request off of the latest master branch to add this feature would be welcome! That gattoool-fix branch was a giant refactoring that ultimately didn't do what we needed, so it's considered abandoned.

andyboeh commented 7 years ago

Yeah, there are actually two possibilities on how to implement this and I'm not yet sure which way to go:

  1. Add a call to char-desc in addition to characteristics and let the user write to the now-known handle. However, the user wouldn't have the chance to retrieve the handle directly and would have to call gatttool to find the handle.
  2. Add a separate char-desc command to pygatt

I suppose option 2 is the cleaner approach..

jornado commented 7 years ago

Did this not go anywhere? I'm experiencing the exact same problem and I guess will have to use another library or gatttool directly?

grodri93 commented 7 years ago

In pygatt/backends/bgapi/bgapi.py: I modified def _get_uuid_type(uuid), instead of returning None, have it return UUIDType.characteristic In pygatt/backends/bgapi/device.py: I commented out line 106 in def char_write_handle

peplin commented 5 years ago

Many improvements to characteristics writes (including long write support) landed in v4.0, now on PyPi. Please give that a try and open a new issue if you are still having problems. Thanks!