Closed shaunmulligan closed 2 years ago
Hi, it's definitely possible to use multiple Bluetooth devices at once with the library. I wrote the module for a University project: a virtual training environment which used 4 Bluetooth devices simultaneously (2 turbo trainers and 2 Sterzo plates). I've never tested with heart rate monitors, but I expect it would be the same. I've pulled out a bit of the code from my project which shows how I handled the multiple connections:
from bleak import BleakClient
import asyncio
from pycycling.sterzo import Sterzo
from pycycling.tacx_trainer_control import TacxTrainerControl, RoadSurface
...
class VirtualTrainingEnvironment:
...
async def run_simulation(self):
loop = asyncio.get_running_loop()
loop.create_task(self.connect_to_turbo(rider_id=0, address=TURBO_1_ADDRESS))
loop.create_task(self.connect_to_steering(rider_id=0, address=STERZO_1_ADDRESS))
loop.create_task(self.connect_to_turbo(rider_id=1, address=TURBO_2_ADDRESS))
loop.create_task(self.connect_to_steering(rider_id=1, address=STERZO_2_ADDRESS))
...
while True:
await asyncio.gather(
self.game_tick(),
asyncio.sleep(self.interval),
)
...
async def connect_to_turbo(self, rider_id, address):
async with BleakClient(address, timeout=30.0) as client:
def my_general_handler(data):
self.turbo_speed_measurements[rider_id] = data.speed
def my_specific_handler(data):
self.turbo_power_measurements[rider_id] = data.instantaneous_power
self.turbos[rider_id] = TacxTrainerControl(client)
self.turbos[rider_id].set_specific_trainer_data_page_handler(my_specific_handler)
self.turbos[rider_id].set_general_fe_data_page_handler(my_general_handler)
...
await asyncio.sleep(300)
async def connect_to_steering(self, rider_id, address):
async with BleakClient(address, timeout=30.0) as client:
def steering_handler(angle):
self.steering_measurements[rider_id].pop(0)
self.steering_measurements[rider_id].append(angle / 30)
await client.is_connected()
sterzo = Sterzo(client)
sterzo.set_steering_measurement_callback(steering_handler)
await sterzo.enable_steering_measurement_notifications()
...
await asyncio.sleep(300)
if __name__ == '__main__':
import os
os.environ["PYTHONASYNCIODEBUG"] = str(1)
vte = VirtualTrainingEnvironment()
asyncio.run(vte.run_simulation())
I'm afraid I'm not entirely sure why your code snippet isn't working. You could try increasing the timeout a bit and see if that helps.
If you figure out what's going wrong please post the solution here :)
Hi @zacharyedwardbull thanks for the quick response. I have been looking at some of the Bleak issues and it seems its a limitation of the Bluez linux implementation. Apparently it doesn't work because bleak runs a scan for each client if you pass BleakClient an address rather than a BleDevice object. So the work around seems to be to run the scanner yourself and then pass the actual BleDevices from that scan to the BleakClient constructor. There is an example here https://github.com/hbldh/bleak/issues/630 that works for me. So I will follow that approach and restructure my code. Thanks for the help!
No worries, good luck with getting it to work. I should have mentioned that I only ever tested multiple devices on macOS Catalina and Windows 10.
Thanks! I got it working now on a linux, the trick was to do the scan separately and pass BLEDevice objects to the BleakClient. Thanks for the help, I will close this for now.
Thanks for this amazing library! I have been playing around with it to get data from my Garmin HRM and 4iiii Powermeter. Both of them work correctly when alone, but I can't seem to get them to connect and read data simultaneously.
As a test case I tried to get data from two heart rate monitors at the same time, you can see the code below. Is there something I am doing wrong or is this a limitation of pycycling? I see its seems possible with the raw Bleak lib: https://github.com/hbldh/bleak/blob/develop/examples/two_devices.py
Thanks again!