Skip to content

Commit e1b147d

Browse files
authored
Merge pull request #36 from jlusiardi/issue_35_read_descriptors
#35 Proposes an extension to access GATT descriptors
2 parents d215ede + c1e422c commit e1b147d

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

examples/read_descriptor.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import gatt
2+
3+
from argparse import ArgumentParser
4+
5+
6+
class AnyDevice(gatt.Device):
7+
def connect_succeeded(self):
8+
super().connect_succeeded()
9+
print("[%s] Connected" % (self.mac_address))
10+
11+
def connect_failed(self, error):
12+
super().connect_failed(error)
13+
print("[%s] Connection failed: %s" % (self.mac_address, str(error)))
14+
15+
def disconnect_succeeded(self):
16+
super().disconnect_succeeded()
17+
print("[%s] Disconnected" % (self.mac_address))
18+
19+
def services_resolved(self):
20+
super().services_resolved()
21+
22+
print("[%s] Resolved services" % (self.mac_address))
23+
for service in self.services:
24+
print("[%s]\tService [%s]" % (self.mac_address, service.uuid))
25+
for characteristic in service.characteristics:
26+
print("[%s]\t\tCharacteristic [%s]" % (self.mac_address, characteristic.uuid))
27+
for descriptor in characteristic.descriptors:
28+
print("[%s]\t\t\tDescriptor [%s] (%s)" % (self.mac_address, descriptor.uuid, descriptor.read_value()))
29+
30+
def descriptor_read_value_failed(self, descriptor, error):
31+
print('descriptor_value_failed')
32+
33+
34+
arg_parser = ArgumentParser(description="GATT Connect Demo")
35+
arg_parser.add_argument('mac_address', help="MAC address of device to connect")
36+
args = arg_parser.parse_args()
37+
38+
print("Connecting...")
39+
40+
manager = gatt.DeviceManager(adapter_name='hci0')
41+
42+
device = AnyDevice(manager=manager, mac_address=args.mac_address)
43+
device.connect()
44+
45+
manager.run()

gatt/gatt_linux.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,13 @@ def characteristic_enable_notifications_failed(self, characteristic, error):
456456
# To be implemented by subclass
457457
pass
458458

459+
def descriptor_read_value_failed(self, descriptor, error):
460+
"""
461+
Called when a descriptor read command failed.
462+
"""
463+
# To be implemented by subclass
464+
pass
465+
459466

460467
class Service:
461468
"""
@@ -505,6 +512,35 @@ def characteristics_resolved(self):
505512
self._connect_characteristic_signals()
506513

507514

515+
class Descriptor:
516+
"""
517+
Represents a GATT Descriptor which can contain metadata or configuration of its characteristic.
518+
"""
519+
520+
def __init__(self, characteristic, path, uuid):
521+
self.characteristic = characteristic
522+
self.uuid = uuid
523+
self._bus = characteristic._bus
524+
self._path = path
525+
self._object = self._bus.get_object('org.bluez', self._path)
526+
527+
def read_value(self, offset=0):
528+
"""
529+
Reads the value of this descriptor.
530+
531+
When successful, the value will be returned, otherwise `descriptor_read_value_failed()` of the related
532+
device is invoked.
533+
"""
534+
try:
535+
val = self._object.ReadValue(
536+
{'offset': dbus.UInt16(offset, variant_level=1)},
537+
dbus_interface='org.bluez.GattDescriptor1')
538+
return val
539+
except dbus.exceptions.DBusException as e:
540+
error = _error_from_dbus_error(e)
541+
self.service.device.descriptor_read_value_failed(self, error=error)
542+
543+
508544
class Characteristic:
509545
"""
510546
Represents a GATT characteristic.
@@ -521,6 +557,13 @@ def __init__(self, service, path, uuid):
521557
self._properties = dbus.Interface(self._object, "org.freedesktop.DBus.Properties")
522558
self._properties_signal = None
523559

560+
descriptor_regex = re.compile(self._path + '/desc[0-9abcdef]{4}$')
561+
self.descriptors = [
562+
Descriptor(self, desc[0], desc[1]['org.bluez.GattDescriptor1']['UUID'])
563+
for desc in self._object_manager.GetManagedObjects().items()
564+
if descriptor_regex.match(desc[0])
565+
]
566+
524567
def _connect_signals(self):
525568
if self._properties_signal is None:
526569
self._properties_signal = self._properties.connect_to_signal('PropertiesChanged', self.properties_changed)

0 commit comments

Comments
 (0)