Skip to content

Commit

Permalink
Merge pull request #678 from hbldh/cb-futures
Browse files Browse the repository at this point in the history
CoreBluetooth callback fixes and cleanups
  • Loading branch information
dlech authored Oct 23, 2021
2 parents dea17d7 + eb7f42c commit ac0d6bf
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 107 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
`Unreleased`_
=============

Fixed
-----
* Fixed ``InvalidStateError`` in CoreBluetooth backend when read and notification
of the same characteristic are used. Fixes #675.
* Fixed reading a characteristic on CoreBluetooth backend also triggers notification
callback.


`0.13.0`_ (2021-10-20)
======================
Expand Down
33 changes: 23 additions & 10 deletions bleak/backends/corebluetooth/CentralManagerDelegate.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,25 +152,38 @@ async def connect(
try:
self._disconnect_callbacks[peripheral.identifier()] = disconnect_callback
future = self.event_loop.create_future()

self._connect_futures[peripheral.identifier()] = future
self.central_manager.connectPeripheral_options_(peripheral, None)
await asyncio.wait_for(future, timeout=timeout)
try:
self.central_manager.connectPeripheral_options_(peripheral, None)
await asyncio.wait_for(future, timeout=timeout)
finally:
del self._connect_futures[peripheral.identifier()]

except asyncio.TimeoutError:
logger.debug(f"Connection timed out after {timeout} seconds.")
del self._disconnect_callbacks[peripheral.identifier()]
future = self.event_loop.create_future()

self._disconnect_futures[peripheral.identifier()] = future
self.central_manager.cancelPeripheralConnection_(peripheral)
await future
try:
self.central_manager.cancelPeripheralConnection_(peripheral)
await future
finally:
del self._disconnect_futures[peripheral.identifier()]

raise

@objc.python_method
async def disconnect(self, peripheral: CBPeripheral) -> None:
future = self.event_loop.create_future()

self._disconnect_futures[peripheral.identifier()] = future
self.central_manager.cancelPeripheralConnection_(peripheral)
await future
del self._disconnect_callbacks[peripheral.identifier()]
try:
self.central_manager.cancelPeripheralConnection_(peripheral)
await future
finally:
del self._disconnect_callbacks[peripheral.identifier()]

@objc.python_method
def _changed_is_scanning(self, is_scanning: bool) -> None:
Expand Down Expand Up @@ -280,7 +293,7 @@ def centralManager_didDiscoverPeripheral_advertisementData_RSSI_(
def did_connect_peripheral(
self, central: CBCentralManager, peripheral: CBPeripheral
) -> None:
future = self._connect_futures.pop(peripheral.identifier(), None)
future = self._connect_futures.get(peripheral.identifier(), None)
if future is not None:
future.set_result(True)

Expand All @@ -301,7 +314,7 @@ def did_fail_to_connect_peripheral(
peripheral: CBPeripheral,
error: Optional[NSError],
) -> None:
future = self._connect_futures.pop(peripheral.identifier(), None)
future = self._connect_futures.get(peripheral.identifier(), None)
if future is not None:
if error is not None:
future.set_exception(BleakError(f"failed to connect: {error}"))
Expand Down Expand Up @@ -331,7 +344,7 @@ def did_disconnect_peripheral(
) -> None:
logger.debug("Peripheral Device disconnected!")

future = self._disconnect_futures.pop(peripheral.identifier(), None)
future = self._disconnect_futures.get(peripheral.identifier(), None)
if future is not None:
if error is not None:
future.set_exception(BleakError(f"disconnect failed: {error}"))
Expand Down
Loading

0 comments on commit ac0d6bf

Please sign in to comment.