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

Only single client connects on Linux #618

Closed
mattdavis90 opened this issue Aug 7, 2021 · 8 comments
Closed

Only single client connects on Linux #618

mattdavis90 opened this issue Aug 7, 2021 · 8 comments
Assignees
Labels
asyncio Problems related to asyncio and multiple clients Backend: BlueZ Issues and PRs relating to the BlueZ backend scanning Issues about scanning/discovery

Comments

@mattdavis90
Copy link

  • bleak version: 0.12.1
  • Python version: 3.9.6
  • Operating System: Linux
  • Kernel: 5.13.6-200.fc34.x86_64
  • BlueZ version: 5.60

Description

I am trying to connect to multiple Bluetooth devices in a single thread but only one connects and notifies. The other seems to hang indefinitely.

What I Did

I have followed issue #105 and tried the code in this comment (#105 (comment)). This didn't work. I get a "starting xxx loop" message for each address then only see a single "connect" message and notifications for one of the devices (seemingly at random as to which one it is). I have also verified that running in separate terminals works as expected. Thanks

@dlech
Copy link
Collaborator

dlech commented Aug 7, 2021

A more up-to-date version of the example is here.

However, we should probably update it to use a separate BleakScanner object for scanning. Since we are providing an address instead of a BLEDevice to the BleakClient in the example, each BleakClient implicitly starts its own BleakScanner. Having two BleakScanners running at the same time can interfere with each other.

@dlech
Copy link
Collaborator

dlech commented Aug 7, 2021

Here is an example: #551 (comment). Although it seems there are potentially issues with connecting and scanning at the same time that need to be resolved as well.

@mattdavis90
Copy link
Author

mattdavis90 commented Aug 7, 2021

Thanks for the very fast response. The code from the linked example didn't work, it resulted in the same output as the previous code I had.

starting D0:CD:84:98:C2:CC loop
starting D9:06:88:2B:8A:28 loop
connect to D9:06:88:2B:8A:28
15 bytearray(b'\x01\x15\x00\x00\x00p?')
15 bytearray(b'\x01\x16\x00\x00\x00\x04B')
15 bytearray(b'\x01\x18\x00\x00\x00\x15G')
15 bytearray(b'\x01\x1a\x00\x00\x00\x0bL')
15 bytearray(b'\x01\x1b\x00\x00\x00\x81N')
15 bytearray(b'\x01\x1d\x00\x00\x00uS')
15 bytearray(b'\x01\x1e\x00\x00\x00\xffU')
15 bytearray(b"\x01 \x00\x00\x00\'[")
15 bytearray(b'\x01!\x00\x00\x00\xcc]')
15 bytearray(b'\x01#\x00\x00\x000c')
disconnect from D9:06:88:2B:8A:28

I tried the code that you posted as causing the issue in 551 and got similar results again.

starting D0:CD:84:98:C2:CC loop
starting D9:06:88:2B:8A:28 loop
connect to D9:06:88:2B:8A:28

Only the second output file had any data;
One - 6B
Two - 285B

Using the code you linked to, where the scanner spawns monitor tasks worked a treat.

scanning...
connected to D0:CD:84:98:C2:CC
connected to D9:06:88:2B:8A:28
received bytearray(b'\x02\x05\x00=\x1b') from D0:CD:84:98:C2:CC
received bytearray(b'\x01\x0b\x00\x00\x00f\x1e') from D9:06:88:2B:8A:28
received bytearray(b'\x02\x05\x00=\x1b') from D0:CD:84:98:C2:CC
received bytearray(b'\x01\r\x00\x00\x00\xf3"') from D9:06:88:2B:8A:28
received bytearray(b'\x02\x06\x00\xd2\x1f') from D0:CD:84:98:C2:CC
received bytearray(b"\x01\x0f\x00\x00\x00\x83\'") from D9:06:88:2B:8A:28
received bytearray(b'\x02\x07\x00a$') from D0:CD:84:98:C2:CC
received bytearray(b'\x01\x11\x00\x00\x00&,') from D9:06:88:2B:8A:28
received bytearray(b'\x02\x08\x00\xf6(') from D0:CD:84:98:C2:CC
received bytearray(b'\x01\x12\x00\x00\x00|.') from D9:06:88:2B:8A:28
received bytearray(b'\x02\t\x00\xa0-') from D0:CD:84:98:C2:CC
done scanning.
received bytearray(b'\x01\x14\x00\x00\x00$3') from D9:06:88:2B:8A:28
received bytearray(b'\x02\n\x00B2') from D0:CD:84:98:C2:CC
received bytearray(b'\x01\x16\x00\x00\x00\xb47') from D9:06:88:2B:8A:28
received bytearray(b'\x02\x0b\x00\xca6') from D0:CD:84:98:C2:CC
disconnected from D9:06:88:2B:8A:28
disconnected from D0:CD:84:98:C2:CC

I'm slightly confused how the last example works but the others don't but I have some workable code for now. Thanks for the help.

@mattdavis90
Copy link
Author

Having looked at the code with the scanner and played around with some of the synchronisation. It looks as though two BleakClient objects and connecting at the same time is causing the strange behaviour. If I add a synchronisation Event between the two connects then I can get both devices connected and notifying.

I had to use two separate callbacks though because the sender parameter was 15 for both connections. Could this be an indication of the issue? Also, after the first device disconnects I stop receiving notifications for the second, again I'm wondering if this is something to do with the sender ID being the same - I haven't actually looked at the library code yet :)

from bleak import BleakClient
import asyncio

temperatureUUID = "45366e80-cf3a-11e1-9ab4-0002a5d5c51b"
ecgUUID = "46366e80-cf3a-11e1-9ab4-0002a5d5c51b"

notify_uuid = "0000{0:x}-0000-1000-8000-00805f9b34fb".format(0x2A5B)


def callback1(sender, data):
    print("1", data)


def callback2(sender, data):
    print("2", data)


async def connect_first(w):
    address = "D0:CD:84:98:C2:CC"
    print("starting", address, "loop")
    async with BleakClient(address, timeout=5.0) as client:
        print("connect to", address)
        try:
            w.set()
            await client.start_notify(notify_uuid, callback1)
            await asyncio.sleep(10)
            await client.stop_notify(notify_uuid)
        except Exception as e:
            print(e)
    print("disconnect from", address)


async def connect_second(w):
    await w.wait()

    address = "D9:06:88:2B:8A:28"
    print("starting", address, "loop")
    async with BleakClient(address, timeout=5.0) as client:
        print("connect to", address)
        try:
            await client.start_notify(notify_uuid, callback2)
            await asyncio.sleep(10)
            await client.stop_notify(notify_uuid)
        except Exception as e:
            print(e)
    print("disconnect from", address)


async def run():
    w = asyncio.Event()
    asyncio.create_task(connect_first(w))
    asyncio.create_task(connect_second(w))
    await asyncio.Event().wait()


if __name__ == "__main__":
    asyncio.run(run())

Give the following output

starting D0:CD:84:98:C2:CC loop
connect to D0:CD:84:98:C2:CC
starting D9:06:88:2B:8A:28 loop
1 bytearray(b'\x020\x00\x0e\xd4')
1 bytearray(b'\x021\x00\xdc\xd7')
connect to D9:06:88:2B:8A:28
1 bytearray(b'\x022\x00\xa9\xdb')
2 bytearray(b'\x01\x7f\x00\x00\x00>\xe0')
1 bytearray(b'\x023\x00i\xdf')
2 bytearray(b'\x01\x81\x00\x00\x00\xf9\xe3')
1 bytearray(b'\x024\x00)\xe3')
2 bytearray(b'\x01\x83\x00\x00\x00\xbc\xe7')
1 bytearray(b'\x025\x00\xe9\xe6')
2 bytearray(b'\x01\x85\x00\x00\x00\x81\xeb')
1 bytearray(b'\x026\x00\xb0\xea')
2 bytearray(b'\x01\x88\x00\x00\x00#\xf1')
1 bytearray(b'\x027\x00p\xee')
2 bytearray(b'\x01\x8a\x00\x00\x00\xf0\xf4')
1 bytearray(b'\x028\x006\xf2')
2 bytearray(b'\x01\x8c\x00\x00\x00\xb2\xf8')
1 bytearray(b'\x029\x00\xf6\xf5')
2 bytearray(b'\x01\x8e\x00\x00\x00u\xfc')
2 bytearray(b'\x01\x90\x00\x00\x00?\x00')
2 bytearray(b'\x01\x92\x00\x00\x00\x06\x04')
disconnect from D0:CD:84:98:C2:CC
disconnect from D9:06:88:2B:8A:28

@elupus
Copy link
Contributor

elupus commented Aug 8, 2021

what happens if you run scanner first to find the devices, and connect using the BleDevice object of the found devices. It could be the "automagic" scanning done by the client that does'nt work.

@hbldh
Copy link
Owner

hbldh commented Aug 9, 2021

Run the scanner first, get the two BLEDevice instances and then send them to the same connect method instead. That should work much better.

@hbldh hbldh added asyncio Problems related to asyncio and multiple clients Backend: BlueZ Issues and PRs relating to the BlueZ backend scanning Issues about scanning/discovery labels Aug 9, 2021
@hbldh hbldh self-assigned this Aug 9, 2021
@mattdavis90
Copy link
Author

mattdavis90 commented Aug 9, 2021

Thanks for the help. I've built up around the BleakScanner and it is working really well. Thanks

@dlech
Copy link
Collaborator

dlech commented Oct 7, 2021

Sounds like this issue has been resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
asyncio Problems related to asyncio and multiple clients Backend: BlueZ Issues and PRs relating to the BlueZ backend scanning Issues about scanning/discovery
Projects
None yet
Development

No branches or pull requests

4 participants