Continuous Scanning + Multi-connect #933
Replies: 2 comments 23 replies
-
Connecting while scanning doesn't really work well with BlueZ. Instead I would just scan for one device at a time, then stop scanning, then connect, then start scanning again for the next device. def match_known_address(device, adv_data):
return device.address in KNOWN_ADDRESS
async def scan_and_connect():
while True:
device = await BleakScanner. find_device_by_filter(match_known_address)
if device is None:
# maybe asyncio.sleep() here for some seconds if you aren't in a hurry
continue
client = BleakClient(device, disconnected_callback=...)
try:
await client.connect()
await client.start_notify(...)
...
except BleakError:
# if failed to connect, this is a no-op, if failed to start notifications, it will disconnect
await client.disconnect()
... |
Beta Was this translation helpful? Give feedback.
-
Maybe something like this would get you started, using the pattern David gave above. As he says, its important to minimize the delay between scanning and trying to connect, so its better to connect as soon as the device is discovered. I am not sure if you need to synchronize access to the I have not included all the sleeps you were doing. As David says, you can sleep if the device wasn't found. You can sleep anywhere and it will just give other coroutines a chance to run, its up to you to figure out what your application's requirements are and what makes it run the best. Also, this is just example code, in real code you would probably want to encapsulate it in a class so that import asyncio
import functools
from bleak import BleakClient, BleakScanner
#lock = asyncio.Lock()
connected_devices = set()
notify_uuid = "00002A37-0000-1000-8000-00805F9B34FB"
def callback(client, characteristic, data):
print(client.address, characteristic, data)
def disconnected_callback(client):
#with lock:
connected_devices.remove(client.address)
print("disconnect from", device.address)
def match_device(device, adv_data):
#with lock:
return adv_data.local_name.startswith('BLE') and device.address not in connected_devices
async def scan_and_connect():
while True:
device = await BleakScanner.find_device_by_filter(match_device)
if device is None:
# maybe asyncio.sleep() here for some seconds if you aren't in a hurry
continue
client = BleakClient(device, disconnected_callback=disconnected_callback)
try:
await client.connect()
print("connected to", device.address)
await client.start_notify(functools.partial(callback, client))
#with lock:
connected_devices.add(device.address)
except BleakError:
# if failed to connect, this is a no-op, if failed to start notifications, it will disconnect
await client.disconnect()
# I'm not sure if manually disconnecting triggers disconnected_callback, (pretty easy to figure this out though)
# if so, you will be getting disconnected_callback called twice
# if not, you should call it here
disconnected_callback(client)
if __name__ == "__main__":
asyncio.run(scan_and_connect()) I have not run it. I'm trying to do something similar to your case, but slightly different. Hope it helps anyway |
Beta Was this translation helpful? Give feedback.
-
Scenario:
I am trying to have a raspberry Pi continuously scan for devices of interest and when they become visible, spin off tasks for each one to connect and start notifications. Then if a device of interest completes this process and disconnects for some time but is seen again later, reconnect and read data. Specifically say I have a heart rate monitor (continuous readings) and a blood pressure monitor (only advertises after a measurement and disconnects after data transmission). When the pi sees these devices I want it to connect to them and start reading. However once the first readings are done I want the pi to keep scanning for these devices if they disconnect to see if they ever become visible again and then connect and start the process over.
I know there has been other discussions around these topics and I have looked at them and tried their suggestions in different combinations but I can't quite get it to work.
Related issues and discussions: #105, #551, #345, #178
What I have tried:
This connects and reads from both devices, however, there is no continuous scanning (I want it to create simultaneous coroutines on the fly I think) additionally once a device disconnects the coroutine is done and therefore the device does not get picked up again. I've tried a couple ways to have the device be discovered again simultaneously but they didn't work and seemed wrong (like restarting a coroutine in the disconnect callback)
Output:
Tryin to get the continuous scanning and connecting/rescanning (Easiest read bottom up)
With this implementation it is able to continuously scan but if fails to connect to both devices. It can connect (albeit it makes duplicate connects and readings and I am not sure why) to the blood pressure monitor and read its data with being able to find it again after disconnection. However while trying to connect to the heart rate monitor at the same time it gets a timeout error as shown below.
Interestingly, after running this code, when I check
bluetoothctl
the heart rate sensor is connected in and I can interact with it...After reading the similar discussions it seems it may be caused by having multiple BleakScanners running in addition to trying to connect to devices but I am not sure because it seems to be connected at the bluez level.
Does anyone have any suggestions for this type of implementation?
Beta Was this translation helpful? Give feedback.
All reactions