Skip to content

Commit

Permalink
Instantiate BaseBleakClient.services collection after service discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
bojanpotocnik authored and dlech committed Nov 23, 2022
1 parent 6520268 commit 5e7d191
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 34 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Changed
* Dropped ``async-timeout`` dependency on Python >= 3.11.
* Deprecated ``BLEDevice.rssi`` and ``BLEDevice.metadata``. Fixes #1025.
* ``BLEDevice`` now uses ``__slots__`` to reduce memory usage.
* ``BaseBleakClient.services`` is now ``None`` instead of empty service collection
until services are discovered.

Fixed
-----
Expand Down
6 changes: 6 additions & 0 deletions bleak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,13 @@ def services(self) -> BleakGATTServiceCollection:
Gets the collection of GATT services available on the device.
The returned value is only valid as long as the device is connected.
Raises:
BleakError: if service discovery has not been performed yet during this connection.
"""
if not self._backend.services:
raise BleakError("Service Discovery has not been performed yet")

return self._backend.services

# I/O methods
Expand Down
6 changes: 2 additions & 4 deletions bleak/backends/bluezdbus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,7 @@ def _cleanup_all(self) -> None:
self._bus = None

# Reset all stored services.
self.services = BleakGATTServiceCollection()
self._services_resolved = False
self.services = None

async def disconnect(self) -> bool:
"""Disconnect from the specified GATT server.
Expand Down Expand Up @@ -587,15 +586,14 @@ async def get_services(
if not self.is_connected:
raise BleakError("Not connected")

if self._services_resolved:
if self.services is not None:
return self.services

manager = await get_global_bluez_manager()

self.services = await manager.get_services(
self._device_path, dangerous_use_bleak_cache
)
self._services_resolved = True

return self.services

Expand Down
4 changes: 1 addition & 3 deletions bleak/backends/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ def __init__(self, address_or_ble_device: Union[BLEDevice, str], **kwargs):
else:
self.address = address_or_ble_device

self.services = BleakGATTServiceCollection()

self._services_resolved = False
self.services: Optional[BleakGATTServiceCollection] = None

self._timeout = kwargs.get("timeout", 10.0)
self._disconnected_callback = kwargs.get("disconnected_callback")
Expand Down
25 changes: 11 additions & 14 deletions bleak/backends/corebluetooth/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
CBPeripheral,
CBPeripheralStateConnected,
)
from Foundation import NSArray, NSData
from Foundation import NSData

from ... import BleakScanner
from ...exc import BleakError, BleakDeviceNotFoundError
Expand Down Expand Up @@ -57,8 +57,6 @@ def __init__(self, address_or_ble_device: Union[BLEDevice, str], **kwargs):
self._central_manager_delegate,
) = address_or_ble_device.details

self._services: Optional[NSArray] = None

def __str__(self):
return "BleakClientCoreBluetooth ({})".format(self.address)

Expand Down Expand Up @@ -91,11 +89,9 @@ async def connect(self, **kwargs) -> bool:
)

def disconnect_callback():
self.services = BleakGATTServiceCollection()
# Ensure that `get_services` retrieves services again, rather
# than using the cached object
self._services_resolved = False
self._services = None
self.services = None

# If there are any pending futures waiting for delegate callbacks, we
# need to raise an exception since the callback will no longer be
Expand Down Expand Up @@ -190,20 +186,22 @@ async def get_services(self, **kwargs) -> BleakGATTServiceCollection:
A :py:class:`bleak.backends.service.BleakGATTServiceCollection` with this device's services tree.
"""
if self._services is not None:
if self.services is not None:
return self.services

services = BleakGATTServiceCollection()

logger.debug("Retrieving services...")
services = await self._delegate.discover_services()
cb_services = await self._delegate.discover_services()

for service in services:
for service in cb_services:
serviceUUID = service.UUID().UUIDString()
logger.debug(
"Retrieving characteristics for service {}".format(serviceUUID)
)
characteristics = await self._delegate.discover_characteristics(service)

self.services.add_service(BleakGATTServiceCoreBluetooth(service))
services.add_service(BleakGATTServiceCoreBluetooth(service))

for characteristic in characteristics:
cUUID = characteristic.UUID().UUIDString()
Expand All @@ -212,7 +210,7 @@ async def get_services(self, **kwargs) -> BleakGATTServiceCollection:
)
descriptors = await self._delegate.discover_descriptors(characteristic)

self.services.add_characteristic(
services.add_characteristic(
BleakGATTCharacteristicCoreBluetooth(
characteristic,
self._peripheral.maximumWriteValueLengthForType_(
Expand All @@ -221,16 +219,15 @@ async def get_services(self, **kwargs) -> BleakGATTServiceCollection:
)
)
for descriptor in descriptors:
self.services.add_descriptor(
services.add_descriptor(
BleakGATTDescriptorCoreBluetooth(
descriptor,
cb_uuid_to_str(characteristic.UUID()),
int(characteristic.handle()),
)
)
logger.debug("Services resolved for %s", str(self))
self._services_resolved = True
self._services = services
self.services = services
return self.services

async def read_gatt_char(
Expand Down
15 changes: 8 additions & 7 deletions bleak/backends/p4android/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,7 @@ async def disconnect(self) -> bool:
self.__callbacks = None

# Reset all stored services.
self.services = BleakGATTServiceCollection()
self._services_resolved = False
self.services = None

return True

Expand Down Expand Up @@ -246,14 +245,16 @@ async def get_services(self) -> BleakGATTServiceCollection:
A :py:class:`bleak.backends.service.BleakGATTServiceCollection` with this device's services tree.
"""
if self._services_resolved:
if self.services is not None:
return self.services

services = BleakGATTServiceCollection()

logger.debug("Get Services...")
for java_service in self.__gatt.getServices():

service = BleakGATTServiceP4Android(java_service)
self.services.add_service(service)
services.add_service(service)

for java_characteristic in java_service.getCharacteristics():

Expand All @@ -263,7 +264,7 @@ async def get_services(self) -> BleakGATTServiceCollection:
service.handle,
self.__mtu - 3,
)
self.services.add_characteristic(characteristic)
services.add_characteristic(characteristic)

for descriptor_index, java_descriptor in enumerate(
java_characteristic.getDescriptors()
Expand All @@ -275,9 +276,9 @@ async def get_services(self) -> BleakGATTServiceCollection:
characteristic.handle,
descriptor_index,
)
self.services.add_descriptor(descriptor)
services.add_descriptor(descriptor)

self._services_resolved = True
self.services = services
return self.services

# IO methods
Expand Down
11 changes: 5 additions & 6 deletions bleak/backends/winrt/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ def max_pdu_size_changed_handler(sender: GattSession, args):
# services did not change while getting services,
# so this is the final result
self.services = get_services_task.result()
self._services_resolved = True
break

logger.debug(
Expand Down Expand Up @@ -463,10 +462,10 @@ async def disconnect(self) -> bool:
self._notification_callbacks.clear()

# Dispose all service components that we have requested and created.
for service in self.services:
service.obj.close()
self.services = BleakGATTServiceCollection()
self._services_resolved = False
if self.services:
for service in self.services:
service.obj.close()
self.services = None

# Without this, disposing the BluetoothLEDevice won't disconnect it
if self._session:
Expand Down Expand Up @@ -616,7 +615,7 @@ async def get_services(
"""

# Return the Service Collection.
if self._services_resolved:
if self.services is not None:
return self.services

logger.debug(
Expand Down

0 comments on commit 5e7d191

Please sign in to comment.