Closed koenvervloesem closed 2 years ago
There are a number of duplicate issues about this already. The recommendation is to use BleakScanner
to find the devices first, then connect when the scanning is done.
Ok, I solved this as you suggested:
import asyncio
import functools
import sys
from bleak import BleakClient, BleakScanner
DEVICE_NAME_UUID = "00002a00-0000-1000-8000-00805f9b34fb"
HEART_RATE_MEASUREMENT_UUID = "00002a37-0000-1000-8000-00805f9b34fb"
addresses = []
heart_rate_sensors = []
def device_found(device, _):
if device.address in addresses:
heart_rate_sensors.append(device)
print(f"Found device {device.name}")
def heart_rate_changed(
device_name: str, handle: int, data: bytearray
):
print(f"{device_name}: {data[1]} bpm")
async def connect(device):
try:
async with BleakClient(device) as client:
device_name = (
await client.read_gatt_char(DEVICE_NAME_UUID)
).decode()
print(f"Connected to {device_name}")
await client.start_notify(
HEART_RATE_MEASUREMENT_UUID,
functools.partial(heart_rate_changed, device_name),
)
print(f"Start notifications for {device_name}...")
while True:
await asyncio.sleep(1)
except asyncio.exceptions.TimeoutError:
print(
f"Can't connect to device {device.address}. Does it run a GATT server?"
)
async def main():
scanner = BleakScanner()
scanner.register_detection_callback(device_found)
await scanner.start()
await asyncio.sleep(5.0)
await scanner.stop()
await asyncio.gather(
*(connect(device) for device in heart_rate_sensors)
)
if __name__ == "__main__":
if len(sys.argv) >= 2:
addresses = sys.argv[1:]
asyncio.run(main())
else:
print(
"Please specify at least one Bluetooth address on the command line."
)
And this works:
$ python3 heart-rate.py EB:76:55:B9:56:18 F3:BE:3E:97:17:A4
Found device F15
Found device InfiniTime
Connected to F15
Start notifications for F15...
Connected to InfiniTime
Start notifications for InfiniTime...
F15: 71 bpm
F15: 71 bpm
InfiniTime: 46 bpm
F15: 71 bpm
F15: 70 bpm
F15: 70 bpm
F15: 70 bpm
F15: 70 bpm
F15: 69 bpm
F15: 69 bpm
F15: 68 bpm
InfiniTime: 49 bpm
F15: 68 bpm
F15: 67 bpm
Description
I'm trying to adapt my heart rate monitor script from https://github.com/hbldh/bleak/issues/613#issuecomment-907613664 to read the Heart Rate Measurement characteristic from multiple BLE devices at the same time. I looked at the two_devices.py example for the approach with
asyncio.gather
.I've tested this with two devices (the PineTime with InfiniTime firmware and a Xanes F15). The script is able to read the heart rate for each of the devices individually. But when I run my adapted script on both devices at the same time, only one of them sends its notification messages.
What I Did
The code:
This uses
asyncio.run
as suggested in https://github.com/hbldh/bleak/issues/613#issuecomment-907640439 to disconnect correctly after an unhandled exception. Thetwo_devices.py
example usesloop.run_until_complete
, but even if I use that approach the script only connects to one device.Running the script for only the PineTime works:
Running the script for only the Xanes F15 works:
Running the script for both devices only shows the notification messages from one (I made sure to wait long enough):
I've tried this a couple of times and I switched the arguments, but it always seems to pick the device listed as the second argument.