Skip to content

Commit

Permalink
Merge branch 'develop' into bluez-battery-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dlech authored Sep 5, 2022
2 parents 9e7cac4 + 9529686 commit 44dd2c8
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 57 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0

Changed
-------
* Changed version check for BlueZ battery workaround to exclude versions >= 5.55.
* ``BleakClient`` methods now raise ``BleakError`` if called when not connected in WinRT backend.
* Extended disconnect timeout to 120 seconds in WinRT backend. Fixes #807.
* Changed version check for BlueZ battery workaround to exclude versions >= 5.55. Merged #976.

Fixed
-----
* Fixed possible ``AttributeError`` when enabling notifications for battery service in BlueZ backend.
* Fixed wrong error message for BlueZ "Operation failed with ATT error". Merged #975.
* Fixed possible ``AttributeError`` when enabling notifications for battery service in BlueZ backend. Merged #976.

`0.16.0`_ (2022-08-31)
======================
Expand Down
131 changes: 77 additions & 54 deletions bleak/backends/winrt/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,9 @@ async def disconnect(self) -> bool:
self._session_closed_events.append(event)
try:
self._requester.close()
async with async_timeout.timeout(10):
# sometimes it can take over one minute before Windows decides
# to end the GATT session/disconnect the device
async with async_timeout.timeout(120):
await event.wait()
finally:
self._session_closed_events.remove(event)
Expand Down Expand Up @@ -499,73 +501,76 @@ async def get_services(self, **kwargs) -> BleakGATTServiceCollection:
A :py:class:`bleak.backends.service.BleakGATTServiceCollection` with this device's services tree.
"""
if not self.is_connected:
raise BleakError("Not connected")

# Return the Service Collection.
if self._services_resolved:
return self.services
else:
logger.debug("Get Services...")

# Each of the get_serv/char/desc_async() methods has two forms, one
# with no args and one with a cache_mode argument
args = []

# If the os-specific use_cached_services arg was given when BleakClient
# was created, the we use the second form with explicit cache mode.
# Otherwise we use the first form with no explicit cache mode which
# allows the OS Bluetooth stack to decide what is best.
if self._use_cached_services is not None:
args.append(
BluetoothCacheMode.CACHED
if self._use_cached_services
else BluetoothCacheMode.UNCACHED
)

services: Sequence[GattDeviceService] = _ensure_success(
await self._requester.get_gatt_services_async(*args),
"services",
"Could not get GATT services",
logger.debug("Get Services...")

# Each of the get_serv/char/desc_async() methods has two forms, one
# with no args and one with a cache_mode argument
args = []

# If the os-specific use_cached_services arg was given when BleakClient
# was created, the we use the second form with explicit cache mode.
# Otherwise we use the first form with no explicit cache mode which
# allows the OS Bluetooth stack to decide what is best.
if self._use_cached_services is not None:
args.append(
BluetoothCacheMode.CACHED
if self._use_cached_services
else BluetoothCacheMode.UNCACHED
)

for service in services:
# Windows returns an ACCESS_DENIED error when trying to enumerate
# characteristics of services used by the OS, like the HID service
# so we have to exclude those services.
if service.uuid in _ACCESS_DENIED_SERVICES:
continue
services: Sequence[GattDeviceService] = _ensure_success(
await self._requester.get_gatt_services_async(*args),
"services",
"Could not get GATT services",
)

self.services.add_service(BleakGATTServiceWinRT(service))
for service in services:
# Windows returns an ACCESS_DENIED error when trying to enumerate
# characteristics of services used by the OS, like the HID service
# so we have to exclude those services.
if service.uuid in _ACCESS_DENIED_SERVICES:
continue

characteristics: Sequence[GattCharacteristic] = _ensure_success(
await service.get_characteristics_async(*args),
"characteristics",
f"Could not get GATT characteristics for {service}",
)
self.services.add_service(BleakGATTServiceWinRT(service))

for characteristic in characteristics:
self.services.add_characteristic(
BleakGATTCharacteristicWinRT(
characteristic, self._session.max_pdu_size - 3
)
)
characteristics: Sequence[GattCharacteristic] = _ensure_success(
await service.get_characteristics_async(*args),
"characteristics",
f"Could not get GATT characteristics for {service}",
)

descriptors: Sequence[GattDescriptor] = _ensure_success(
await characteristic.get_descriptors_async(*args),
"descriptors",
f"Could not get GATT descriptors for {service}",
for characteristic in characteristics:
self.services.add_characteristic(
BleakGATTCharacteristicWinRT(
characteristic, self._session.max_pdu_size - 3
)
)

descriptors: Sequence[GattDescriptor] = _ensure_success(
await characteristic.get_descriptors_async(*args),
"descriptors",
f"Could not get GATT descriptors for {service}",
)

for descriptor in descriptors:
self.services.add_descriptor(
BleakGATTDescriptorWinRT(
descriptor,
str(characteristic.uuid),
characteristic.attribute_handle,
)
for descriptor in descriptors:
self.services.add_descriptor(
BleakGATTDescriptorWinRT(
descriptor,
str(characteristic.uuid),
characteristic.attribute_handle,
)
)

logger.info("Services resolved for %s", str(self))
self._services_resolved = True
return self.services
logger.info("Services resolved for %s", str(self))
self._services_resolved = True
return self.services

# I/O methods

Expand All @@ -589,6 +594,9 @@ async def read_gatt_char(
(bytearray) The read data.
"""
if not self.is_connected:
raise BleakError("Not connected")

use_cached = kwargs.get("use_cached", False)

if not isinstance(char_specifier, BleakGATTCharacteristic):
Expand Down Expand Up @@ -628,6 +636,9 @@ async def read_gatt_descriptor(self, handle: int, **kwargs) -> bytearray:
(bytearray) The read data.
"""
if not self.is_connected:
raise BleakError("Not connected")

use_cached = kwargs.get("use_cached", False)

descriptor = self.services.get_descriptor(handle)
Expand Down Expand Up @@ -666,6 +677,9 @@ async def write_gatt_char(
response (bool): If write-with-response operation should be done. Defaults to `False`.
"""
if not self.is_connected:
raise BleakError("Not connected")

if not isinstance(char_specifier, BleakGATTCharacteristic):
characteristic = self.services.get_characteristic(char_specifier)
else:
Expand Down Expand Up @@ -698,6 +712,9 @@ async def write_gatt_descriptor(
data (bytes or bytearray): The data to send.
"""
if not self.is_connected:
raise BleakError("Not connected")

descriptor = self.services.get_descriptor(handle)
if not descriptor:
raise BleakError("Descriptor with handle {0} was not found!".format(handle))
Expand Down Expand Up @@ -742,6 +759,9 @@ def callback(sender, data):
notification request, given that the characteristic supports notifications as well as indications.
"""
if not self.is_connected:
raise BleakError("Not connected")

if inspect.iscoroutinefunction(callback):

def bleak_callback(s, d):
Expand Down Expand Up @@ -813,6 +833,9 @@ async def stop_notify(
directly by the BleakGATTCharacteristic object representing it.
"""
if not self.is_connected:
raise BleakError("Not connected")

if not isinstance(char_specifier, BleakGATTCharacteristic):
characteristic = self.services.get_characteristic(char_specifier)
else:
Expand Down
2 changes: 1 addition & 1 deletion bleak/exc.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def dbus_error_details(self) -> Optional[str]:
details = self.args[1]
# Some error descriptions can be further parsed to be even more helpful
if "ATT error: 0x" in details:
more_detail = CONTROLLER_ERROR_CODES.get(
more_detail = PROTOCOL_ERROR_CODES.get(
int(details.rsplit("x")[1], 16), "Unknown code"
)
details += f" ({more_detail})"
Expand Down

0 comments on commit 44dd2c8

Please sign in to comment.