Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

disconnected_callback called with the backend object instead of BleakClient #1200

Closed
deymo opened this issue Jan 13, 2023 · 0 comments · Fixed by #1256
Closed

disconnected_callback called with the backend object instead of BleakClient #1200

deymo opened this issue Jan 13, 2023 · 0 comments · Fixed by #1256
Labels
bug Something isn't working

Comments

@deymo
Copy link

deymo commented Jan 13, 2023

  • bleak version: v0.19.5
  • Python version: 3.10.9
  • Operating System: Debian
  • BlueZ version (bluetoothctl -v) in case of Linux: 5.66

Description

When creating a BleakClient we can pass a callback to the disconnected_callback parameter to be called when the device disconnects. The type for this parameter is Optional[Callable[[BleakClient], None]] and the documentation for this parameter says "The callable must take one argument, which will be this client object." so I'm assuming the expected parameter is a BleakClient object.

However, the parameter is just forwarded to the backend, where at least in bluez, winrt and corebluetooth it is called with:

  if self._disconnected_callback is not None:
     self._disconnected_callback(self)

where self is the backend type.

In general this is not much of a difference since most methods and properties in BleakClient are just forwarded to the self._backend but in the case of start_notify the backend and BleakClient are different:.

BleakClient.start_notify takes a callback with two arguments (Callable[[BleakGATTCharacteristic, bytearray], Union[None, Awaitable[None]]) but it wraps with a functools.partial or equivalent asyncio thing so that the backend gets a callback with only one argument (the bytearray). Also, the first argument (the characteristic) is converted to a BleakGATTCharacteristic if not already, so passing a string to cli.start_notify gets an error since the backend assumes it was already converted to the backend's type.

What I Did

The example to reproduce this requires to disconnect and reconnect the device. Start the example until you see some "on_notification" messages, then get the device out of range until you see the "on_disconnect" and then back in range so the reconnect triggers.

import asyncio, bleak, sys

CHAR_UUID = 'some uuid' # Use a characteristic that sends periodic notifications

def on_notification(cli, data):
    print('on_notification', type(cli), data)

async def on_disconnect_async(cli):
    await cli.connect()
    await cli.start_notify(CHAR_UUID, on_notification)

def on_disconnect(cli):
    print('on_disconnect', type(cli))
    asyncio.get_event_loop().call_soon(asyncio.ensure_future, on_disconnect_async(cli))

async def main():
    cli = bleak.BleakClient(sys.argv[1], disconnected_callback=on_disconnect)
    await cli.connect()
    await cli.start_notify(CHAR_UUID, on_notification)
    print('connected')
    while True:
        await asyncio.sleep(1)

if __name__ == '__main__':
    asyncio.run(main())

The output is roughly:

connected
on_notification <class 'bleak.backends.bluezdbus.characteristic.BleakGATTCharacteristicBlueZDBus'> bytearray(b'.....')
....
on_disconnect <class 'bleak.backends.bluezdbus.client.BleakClientBlueZDBus'>

followed by this exception:

  File ".../test.py", line 10, in on_disconnect_async
    await cli.start_notify(CHAR_UUID, on_notification)
  File ".../bleak/backends/bluezdbus/client.py", line 873, in start_notify
    self._notification_callbacks[characteristic.path] = callback
AttributeError: 'str' object has no attribute 'path'
@dlech dlech added the bug Something isn't working label Jan 13, 2023
@dlech dlech linked a pull request Mar 17, 2023 that will close this issue
@dlech dlech mentioned this issue Mar 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants