Skip to content

Commit

Permalink
Changed Service identification to handles for Windows backend.
Browse files Browse the repository at this point in the history
Fixes #445 for Windows
Fixes #362 for Windows
  • Loading branch information
hbldh committed Feb 25, 2021
1 parent 3e79f4a commit e857fd6
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 37 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ Fixed
backend. Merged #401.
* Fixed RSSI missing in discovered devices on macOS backend. Merged #400.
* Fixed a broken check for the correct adapter in ``BleakClientBlueZDBus``.
* Fixed #445 and #362 for Windows.

Changed
~~~~~~~

* Using handles to identify the services. Added `handle` abstract property to `BleakGATTService`
and storing the services by handle instead of UUID.


`0.10.0`_ (2020-12-11)
Expand Down
9 changes: 8 additions & 1 deletion bleak/backends/bluezdbus/characteristic.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@
class BleakGATTCharacteristicBlueZDBus(BleakGATTCharacteristic):
"""GATT Characteristic implementation for the BlueZ DBus backend"""

def __init__(self, obj: dict, object_path: str, service_uuid: str):
def __init__(
self, obj: dict, object_path: str, service_uuid: str, service_handle: int
):
super(BleakGATTCharacteristicBlueZDBus, self).__init__(obj)
self.__descriptors = []
self.__path = object_path
self.__service_uuid = service_uuid
self.__service_handle = service_handle

# D-Bus object path contains handle as last 4 characters of 'charYYYY'
self._handle = int(object_path[-4:], 16)
Expand All @@ -43,6 +46,10 @@ def service_uuid(self) -> str:
"""The uuid of the Service containing this characteristic"""
return self.__service_uuid

@property
def service_handle(self) -> int:
return self.__service_handle

@property
def handle(self) -> int:
"""The handle of this characteristic"""
Expand Down
4 changes: 3 additions & 1 deletion bleak/backends/bluezdbus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,9 @@ async def get_services(self, **kwargs) -> BleakGATTServiceCollection:
for char, object_path in _chars:
_service = list(filter(lambda x: x.path == char["Service"], self.services))
self.services.add_characteristic(
BleakGATTCharacteristicBlueZDBus(char, object_path, _service[0].uuid)
BleakGATTCharacteristicBlueZDBus(
char, object_path, _service[0].uuid, _service[0].handle
)
)

# D-Bus object path contains handle as last 4 characters of 'charYYYY'
Expand Down
5 changes: 5 additions & 0 deletions bleak/backends/bluezdbus/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def uuid(self) -> str:
"""The UUID to this service"""
return self.obj["UUID"]

@property
def handle(self) -> str:
"""The integer handle of this service"""
raise NotImplementedError("This needs to be implemented!")

@property
def characteristics(self) -> List[BleakGATTCharacteristicBlueZDBus]:
"""List of characteristics for this service"""
Expand Down
8 changes: 7 additions & 1 deletion bleak/backends/characteristic.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,20 @@ def __init__(self, obj: Any):
self.obj = obj

def __str__(self):
return "{0}: {1}".format(self.uuid, self.description)
return f"{self.uuid} (Handle: {self.handle}): {self.description}"

@property
@abc.abstractmethod
def service_uuid(self) -> str:
"""The UUID of the Service containing this characteristic"""
raise NotImplementedError()

@property
@abc.abstractmethod
def service_handle(self) -> int:
"""The integer handle of the Service containing this characteristic"""
raise NotImplementedError()

@property
@abc.abstractmethod
def handle(self) -> int:
Expand Down
3 changes: 0 additions & 3 deletions bleak/backends/corebluetooth/characteristic.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ def __init__(self, obj: CBCharacteristic):
]
self._uuid = cb_uuid_to_str(self.obj.UUID())

def __str__(self):
return "{0}: {1}".format(self.uuid, self.description)

@property
def service_uuid(self) -> str:
"""The uuid of the Service containing this characteristic"""
Expand Down
3 changes: 0 additions & 3 deletions bleak/backends/corebluetooth/descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ def __init__(
self.__characteristic_uuid = characteristic_uuid
self.__characteristic_handle = characteristic_handle

def __str__(self):
return "{0}: (Handle: {1})".format(self.uuid, self.handle)

@property
def characteristic_handle(self) -> int:
"""handle for the characteristic that this descriptor belongs to"""
Expand Down
5 changes: 5 additions & 0 deletions bleak/backends/corebluetooth/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ def __init__(self, obj: CBService):
super().__init__(obj)
self.__characteristics = []

@property
def handle(self) -> str:
"""The integer handle of this service"""
raise NotImplementedError("This needs to be implemented!")

@property
def uuid(self) -> str:
"""UUID for this service."""
Expand Down
2 changes: 1 addition & 1 deletion bleak/backends/descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def __init__(self, obj: Any):
self.obj = obj

def __str__(self):
return "{0}: {1}".format(self.uuid, self.description)
return f"{self.uuid} (Handle: {self.handle}): {self.description}"

@property
@abc.abstractmethod
Expand Down
8 changes: 5 additions & 3 deletions bleak/backends/dotnet/characteristic.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ def __init__(self, obj: GattCharacteristic):
if (self.obj.CharacteristicProperties & v)
]

def __str__(self):
return "[{0}] {1}: {2}".format(self.handle, self.uuid, self.description)

@property
def service_uuid(self) -> str:
"""The uuid of the Service containing this characteristic"""
return self.obj.Service.Uuid.ToString()

@property
def service_handle(self) -> int:
"""The integer handle of the Service containing this characteristic"""
return int(self.obj.Service.AttributeHandle)

@property
def handle(self) -> int:
"""The handle of this characteristic"""
Expand Down
3 changes: 0 additions & 3 deletions bleak/backends/dotnet/descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ def __init__(
self.__characteristic_uuid = characteristic_uuid
self.__characteristic_handle = characteristic_handle

def __str__(self):
return "{0}: (Handle: {1})".format(self.uuid, self.handle)

@property
def characteristic_handle(self) -> int:
"""handle for the characteristic that this descriptor belongs to"""
Expand Down
5 changes: 5 additions & 0 deletions bleak/backends/dotnet/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ def __init__(self, obj: GattDeviceService):
# BleakGATTCharacteristicDotNet(c) for c in obj.GetAllCharacteristics()
]

@property
def handle(self) -> str:
"""The handle of this service"""
return int(self.obj.AttributeHandle)

@property
def uuid(self) -> str:
"""UUID for this service."""
Expand Down
42 changes: 32 additions & 10 deletions bleak/backends/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ def __init__(self, obj):
self.obj = obj

def __str__(self):
return "{0}: {1}".format(self.uuid, self.description)
return f"{self.uuid} (Handle: {self.handle}): {self.description}"

@property
@abc.abstractmethod
def handle(self) -> str:
"""The handle of this service"""
raise NotImplementedError()

@property
@abc.abstractmethod
Expand Down Expand Up @@ -91,34 +97,50 @@ def __iter__(self) -> Iterator[BleakGATTService]:

@property
def services(self) -> dict:
"""Returns dictionary of UUID strings to BleakGATTService"""
"""Returns dictionary of handles mapping to BleakGATTService"""
return self.__services

@property
def characteristics(self) -> dict:
"""Returns dictionary of handles to BleakGATTCharacteristic"""
"""Returns dictionary of handles mapping to BleakGATTCharacteristic"""
return self.__characteristics

@property
def descriptors(self) -> dict:
"""Returns a dictionary of integer handles to BleakGATTDescriptor"""
"""Returns a dictionary of integer handles mapping to BleakGATTDescriptor"""
return self.__descriptors

def add_service(self, service: BleakGATTService):
"""Add a :py:class:`~BleakGATTService` to the service collection.
Should not be used by end user, but rather by `bleak` itself.
"""
if service.uuid not in self.__services:
self.__services[service.uuid] = service
if service.handle not in self.__services:
self.__services[service.handle] = service
else:
raise BleakError(
"This service is already present in this BleakGATTServiceCollection!"
)

def get_service(self, _uuid: Union[str, UUID]) -> BleakGATTService:
"""Get a service by UUID string"""
return self.services.get(str(_uuid).lower(), None)
def get_service(self, specifier: Union[int, str, UUID]) -> BleakGATTService:
"""Get a service by handle (int) or UUID (str or uuid.UUID)"""
if isinstance(specifier, int):
return self.services.get(specifier, None)
else:
_specifier = str(specifier).lower()
# Assume uuid usage.
x = list(
filter(
lambda x: x.uuid.lower() == _specifier,
self.services.values(),
)
)
if len(x) > 1:
raise BleakError(
"Multiple Services with this UUID, refer to your desired service by the `handle` attribute instead."
)
else:
return x[0] if x else None

def add_characteristic(self, characteristic: BleakGATTCharacteristic):
"""Add a :py:class:`~BleakGATTCharacteristic` to the service collection.
Expand All @@ -127,7 +149,7 @@ def add_characteristic(self, characteristic: BleakGATTCharacteristic):
"""
if characteristic.handle not in self.__characteristics:
self.__characteristics[characteristic.handle] = characteristic
self.__services[characteristic.service_uuid].add_characteristic(
self.__services[characteristic.service_handle].add_characteristic(
characteristic
)
else:
Expand Down
23 changes: 12 additions & 11 deletions examples/service_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async def run(address, debug=False):
log.info("Connected: {0}".format(x))

for service in client.services:
log.info("[Service] {0}: {1}".format(service.uuid, service.description))
log.info(f"[Service] {service}")
for char in service.characteristics:
if "read" in char.properties:
try:
Expand All @@ -40,19 +40,20 @@ async def run(address, debug=False):
else:
value = None
log.info(
"\t[Characteristic] {0}: (Handle: {1}) ({2}) | Name: {3}, Value: {4} ".format(
char.uuid,
char.handle,
",".join(char.properties),
char.description,
value,
)
f"\t[Characteristic] {char} ({','.join(char.properties)}), Value: {value}"
)

for descriptor in char.descriptors:
value = await client.read_gatt_descriptor(descriptor.handle)
try:
value = bytes(
await client.read_gatt_descriptor(descriptor.handle)
)
except Exception as e:
value = str(e).encode()
log.info(
"\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
descriptor.uuid, descriptor.handle, bytes(value)
f"\t\t[Descriptor] {descriptor}) | Value: {value} ".format(
descriptor.uuid,
descriptor.handle,
)
)

Expand Down

0 comments on commit e857fd6

Please sign in to comment.