question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can't connect to 2 BLE clients in parallel in Buster RPI4

See original GitHub issue
  • bleak version: 0.8.0
  • Python version: 3.8.5
  • Operating System: Debian 10 (Buster)
  • BlueZ version (bluetoothctl -v) in case of Linux: 5.54

Description

related to #345 #215
I tried to connect to two clients (Nordic boards) the context is connecting over BLE from RPI4 to NORDIC over NORDIC dongle.

What I Did

connect to two clients in parallels for data notifications from clients.


from bleak import BleakClient
import asyncio

notify_uuid = "04831524-6c9d-6ca9-5d41-03ad4fff4abb"


def callback(sender, data):
    print(sender, data)


def run(addresses):
    loop = asyncio.get_event_loop()

    tasks = asyncio.gather(
        *(connect_to_device(address, loop) for address in addresses)
    )

    loop.run_until_complete(tasks)


async def connect_to_device(address, loop):
    print("starting", address, "loop")
    async with BleakClient(address, loop=loop, timeout=10.0) as client:

        print("connect to", address)
        try:
            await client.start_notify(notify_uuid, callback)
            await asyncio.sleep(10.0)
            await client.stop_notify(notify_uuid)
        except Exception as e:
            print(address + " : " + str(e))

    print("disconnect from", address)

if __name__ == "__main__":
    run(['D0:6D:E5:40:07:D3', 'FE:5D:07:FE:7A:93' ])

Output

try connecting to both clients in parallel - managed to connect only to 1 client at a time, never connected to both in parallel:

test 1: starting D0:6D:E5:40:07:D3 loop starting FE:5D:07:FE:7A:93 loop connect to FE:5D:07:FE:7A:93 21 bytearray(b’\x01\x00\x00\x00\x02\x81\xbfL\x15’) 21 bytearray(b’\x02\x00\x00\x00\x08O,9\xb2’) 21 bytearray(b’\x03\x00\x00\x00\x08\xff\x05Y\x8f’) 21 bytearray(b’\x04\x00\x00\x00\x0fLL\x1d\xa3’) 21 bytearray(b’\x05\x00\x00\x00\ns\x91\x17\xee’) 21 bytearray(b’\x06\x00\x00\x00\x02\x91cl\xa7’) 21 bytearray(b’\x07\x00\x00\x00\x08?\xa3\xd9z’) 21 bytearray(b’\x08\x00\x00\x00V\x1dHZt’) 21 bytearray(b’\t\x00\x00\x00\x10\x08\x85\x85\xd6’) 21 bytearray(b’\n\x00\x00\x00\xc1\xff\xff\xff\xff\xff\xff\xff\xff\x01\xe6\x15\xdd\xc3’) 21 bytearray(b’\x0b\x00\x00\x00\x02 \xa7\xfc_‘) 21 bytearray(b’\x0c\x00\x00\x00\x08.\x92\t\r’) 21 bytearray(b’\r\x00\x00\x00\x08\x9e\xbbi0’) 21 bytearray(b’\x0e\x00\x00\x00\x0f\xedT\xad\xe9’) 21 bytearray(b’\x0f\x00\x00\x00\n\xd2\x89\xa7\xa4’) 21 bytearray(b’\x10\x00\x00\x00\x02\xb3\x01\xccH’) 21 bytearray(b’\x11\x00\x00\x00\x08\x1d\xc1y\x95’) 21 bytearray(b’\x12\x00\x00\x00V>\xc7\n^‘) 21 bytearray(b’\x13\x00\x00\x00\x10+\n\xd5\xfc’) 21 bytearray(b’\x14\x00\x00\x00\xc2\xff\xff\xff\xff\xff\xff\xff\xff\x01\t\xc7\xc3\x85’) disconnect from FE:5D:07:FE:7A:93 connect to D0:6D:E5:40:07:D3 21 bytearray(b’\x01\x00\x00\x00\x02\x81\xbfL\x15’) 21 bytearray(b’\x02\x00\x00\x00\x08O,9\xb2’) 21 bytearray(b’\x03\x00\x00\x00\x07n\x18\xe6\x1f’) 21 bytearray(b’\x04\x00\x00\x00/\x84ls\x98’) 21 bytearray(b’\x05\x00\x00\x00\ns\x91\x17\xee’) 21 bytearray(b’\x06\x00\x00\x00\x10\xd9\x12\xd5T’) 21 bytearray(b’\x07\x00\x00\x00LVR1234567890123_\xed\v’) 21 bytearray(b’\x08\x00\x00\x00\x12\x94\xcd\xeb\x05’) 21 bytearray(b’\t\x00\x00\x00\x0b\xe4L\xe0\‘) 21 bytearray(b’\n\x00\x00\x002.0.0.20000e>x0’) 21 bytearray(b’\x0b\x00\x00\x00\x1av?\x90L’) 21 bytearray(b’\x0c\x00\x00\x00\x020{\xdc\xed’) 21 bytearray(b’\r\x00\x00\x00\x10\xc8#\x05#‘) 21 bytearray(b’\x0e\x00\x00\x00\x03\xc6\x18\x1b\xe0’) 21 bytearray(b’\x0f\x00\x00\x00\x1a\xb6\x99\x10\xb9’) 21 bytearray(b’\x10\x00\x00\x00\x02\xb3\x01\xccH’) 21 bytearray(b’\x11\x00\x00\x00\x10KY\x15\x86’) 21 bytearray(b’\x12\x00\x00\x00\x04\xe6\xf7o\xdb’) 21 bytearray(b’\x13\x00\x00\x00\x1a5\xe3\x00\x1c’) 21 bytearray(b’\x14\x00\x00\x00\x02s\xa7L\xbd’) 21 bytearray(b’\x15\x00\x00\x00\x10\x8b\xff\x95s’) 21 bytearray(b’\x16\x00\x00\x00\x05\xb0a\xe8Y’) 21 bytearray(b’\x17\x00\x00\x00\x1a\xf5E\x80\xe9’) 21 bytearray(b’\x18\x00\x00\x00\x02rJ\xbcx’) 21 bytearray(b’\x19\x00\x00\x00\x10\x8a\x12e\xb6’) 21 bytearray(b’\x1a\x00\x00\x00\x06\x0b\xdd\x11\x05’) 21 bytearray(b’\x1b\x00\x00\x00\x02\xa20\x1c?‘) 21 bytearray(b’\x1c\x00\x00\x00\x08\xac\x05\xe9m’) 21 bytearray(b’\x1d\x00\x00\x00\x08\x1c,\x89P’) 21 bytearray(b’\x1e\x00\x00\x00\x0fo\xc3M\x89’) 21 bytearray(b’\x1f\x00\x00\x00\nP\x1eG\xc4’) 21 bytearray(b’ \x00\x00\x00\x025\xb9\xed\xe9’) 21 bytearray(b’!\x00\x00\x00\x08\x9byX4’) 21 bytearray(b’“\x00\x00\x00Y)b\x94o’) 21 bytearray(b’#\x00\x00\x00\x10\xad\xb2\xf4]‘) 21 bytearray(b’$\x00\x00\x00\xc2\xff\xff\xff\xff\xff\xff\xff\xff\x01\xbd\x83\x15.‘) 21 bytearray(b’%\x00\x00\x00\x02E6\r!‘) 21 bytearray(b’&\x00\x00\x00\x08\x8b\xa5x\x86’) 21 bytearray(b”'\x00\x00\x00\x08;\x8c\x18\xbb") 21 bytearray(b’(\x00\x00\x00\x0fI\x8e,\xa7’) 21 bytearray(b’)\x00\x00\x00\nvS&\xea’) 21 bytearray(b’*\x00\x00\x00\x02\x94\xa1]\xa3’) 21 bytearray(b’+\x00\x00\x00\x08:a\xe8~‘) 21 bytearray(b’,\x00\x00\x00YH\xdc\xa4\xd0’) disconnect from D0:6D:E5:40:07:D3

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
cshablincommented, Jun 3, 2021

Looking through existing issues, I came across this which is likely to be a challenge as I’m working with a system with two, BLE-connected devices, one of which has a penchant to disconnect sporadically.

“When doing a connection in a BleakClient with a string address, the BleakClient dows a BLE Scan to ensure that that the device is seen by the backend system.” caught my eye. At https://github.com/hbldh/bleak/blob/develop/bleak/backends/bluezdbus/client.py#L56

def __init__(self, address_or_ble_device: Union[BLEDevice, str], **kwargs):

Does this mean that at least some of the two-device challenge can be avoided by doing a scan and passing the BLEDevice to the constructor?

(There will still be challenges as one of the interactions with the app is to change devices, on the fly.)

yes, be aware that this issue is only in Linux, on window it works fine connecting to 2 devices by string.

1reaction
hbldhcommented, Nov 24, 2020

I also wrote a more advanced, verbose two client script while debugging. Sharing that one as well, in case you or someone else might find it useful:

import sys
import asyncio
import logging
from typing import List

from bleak import BleakClient, BleakScanner
from bleak.backends.device import BLEDevice

logger = logging.getLogger("bleak.examples.two_devices")
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
handler.setFormatter(
    logging.Formatter(fmt="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s")
)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)


def callback(sender, data):
    print(sender, data)


async def run(addresses, notification_uuids):
    devices = await scan_for_devices(addresses)
    tasks = asyncio.gather(
        *(
            connect_to_device(device, n_uuid)
            for device, n_uuid in zip(devices, notification_uuids)
        )
    )
    await tasks


async def scan_for_devices(addresses: List[str]) -> List[BLEDevice]:
    addresses = [a.lower() for a in addresses]
    s = BleakScanner()
    logger.debug("Detecting devices...")
    devices = [await s.find_device_by_address(address) for address in addresses]
    for d in devices:
        if d:
            logger.debug(f"Detected {d}...")
    if None in devices:
        # We did not find all desired devices...
        undetected_devices = list(
            set(addresses).difference(
                list(
                    filter(
                        lambda x: x in [d.address.lower() for d in devices if d],
                        addresses,
                    )
                )
            )
        )
        raise ValueError(
            f"Could not find the following device(s): {undetected_devices}..."
        )
    return devices


async def connect_to_device(address: BLEDevice, notification_uuid: str):
    logger.info(f"Starting {address} loop...")
    async with BleakClient(address, timeout=20.0) as client:
        logger.info(f"Connected to {address}...")
        try:
            await client.start_notify(notification_uuid, callback)
            for i in range(10):
                r = await client.read_gatt_char("00002A25-0000-1000-8000-00805f9b34fb")
                logger.debug(f"[{address}] Serial Number String: {r}")
                await asyncio.sleep(6.0)
            await client.stop_notify(notification_uuid)
        except Exception as e:
            logger.error(e)
    logger.info(f"Disconnected to {address}...")


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    # Send a list of addresses to connect to and corresponding array of uuids to start notifications on.
    loop.run_until_complete(
        run(
            [
                "EF:A6:0D:2A:30:55",
                "24:71:89:CC:09:05"
            ],
            [
                "c9f60023-9f9b-fba4-5847-7fd701bf59f2",
                "0000{0:x}-0000-1000-8000-00805f9b34fb".format(0xFFE1),
            ],
        )
    )
Read more comments on GitHub >

github_iconTop Results From Across the Web

multiple BT connection - Raspberry Pi Forums
I would like to connect to my raspberry multiple BLE devices. using nRF connect I can connect just with one smartphone.
Read more >
Bluepy BLE Disconnecting after receiving several packets ...
I have the same issue with multiple disconnects between a RPI client and ESP32 BLE peripheral(server). When using the "nRF Connect" app on...
Read more >
bleak - Bountysource
I'm trying to connect to a BLE device via bleak - it works fine when I use my script on Windows 10, but...
Read more >
Using BLE Devices with a Raspberry Pi - Argenox
The quickest way to do this is right click on PuTTY interface and select "Restart Session".
Read more >
Building Qt 5.12 LTS for Raspberry Pi on Raspberry Pi OS
Install the build. The compilation should finnish without any errors, if it does not, double check that you have all the dependecies installed...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found