bleak: Hanging on "async with BleakClient..."

  • bleak version: 0.5.0-develop
  • Operating System: macOS 10.14.6 (on early 2015 Macbook Air)

Description

In running the examples on MacOS, everything hangs after/within async with BleakClient(address, loop=loop) as client: (within run) i.e. the subsequent typical example x = await client.is_connected or any other calls do not appear to run. Despite this, the OS does indicate that the BLE device is connected indefinitely until the script is stopped. Everything appears to be working fine on Windows.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 22 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I will include the changes in #213 in a version 0.7.X release as soon as someone confirms that it is still present.

Hello, I can confirm that the issue is still present for me with v0.7.0 on macOS 10.14.6. I updated to bleak 0.7.0 and was still having this problem. I added this line as a workaround and it seems to have solved the issue for me:

if not self.connected_peripheral_delegate:

Here is the context:

@objc.python_method
def did_connect_peripheral(self, central, peripheral):
    logger.debug(
        "Successfully connected to device uuid {}".format(
            peripheral.identifier().UUIDString()
        )
    )
    if not self.connected_peripheral_delegate:
        peripheralDelegate = PeripheralDelegate.alloc().initWithPeripheral_(peripheral)
        self.connected_peripheral_delegate = peripheralDelegate
        self._connection_state = CMDConnectionState.CONNECTED

I have merged #227 into develop and will make a version 0.7.0 release later today with those changes as well as a lot of others. If the “fire twice” problem is still left after release of version 0.7.0, I will include the changes in #213 in a version 0.7.X release as soon as someone confirms that it is still present.

Make a pull request to develop, solving this issue and I will merge it and schedule it for the 0.6.2 release.

Created #213

I pulled in whatever pip pulled:

cat __version__.py

# -*- coding: utf-8 -*-

__version__ = "0.6.1"

I have generated a diff file based on @adammark comment, and used it to patch the version after pip install

@@ -202,9 +202,10 @@
                 peripheral.identifier().UUIDString()
             )
         )
-        peripheralDelegate = PeripheralDelegate.alloc().initWithPeripheral_(peripheral)
-        self.connected_peripheral_delegate = peripheralDelegate
-        self._connection_state = CMDConnectionState.CONNECTED
+        if not self.connected_peripheral_delegate:
+            peripheralDelegate = PeripheralDelegate.alloc().initWithPeripheral_(peripheral)
+            self.connected_peripheral_delegate = peripheralDelegate
+            self._connection_state = CMDConnectionState.CONNECTED
 
     def centralManager_didFailToConnectPeripheral_error_(
         self, centralManager: CBCentralManager, peripheral: CBPeripheral, error: NSError

This solved the issue for me - but now has to be patched part of each pip install

I’ve been playing with the develop branch and I saw something similar happen when connecting to certain devices with OS X. The best I can tell is that centralManager_didConnectPeripheral_ is being fired twice, creating two peripheral delegates. The first delegate proceeds with discovering services and characteristics, but by this point the central manager has a handle to a different delegate, which I suppose is either doing nothing or is otherwise blocked. Therefore client.connect() never resolves.

I can’t say why the callback is being fired twice for some devices and not others, but I was able to work around the problem with a one line check here:

def centralManager_didConnectPeripheral_(self, central, peripheral):
    logger.debug(
        "Successfully connected to device uuid {}".format(
            peripheral.identifier().UUIDString()
        )
    )
    if not self.connected_peripheral_delegate:
        peripheralDelegate = PeripheralDelegate.alloc().initWithPeripheral_(peripheral)
        self.connected_peripheral_delegate = peripheralDelegate
        self._connection_state = CMDConnectionState.CONNECTED