hbldh / bleak

A cross platform Bluetooth Low Energy Client for Python using asyncio
MIT License
1.73k stars 289 forks source link

Possible to run notification on two different devices at once. #215

Closed kswann-imb closed 4 years ago

kswann-imb commented 4 years ago

Description

I'm trying to connect to some heart rate monitors and I can successfully connect to 1 and read the data properly, but I would like to connect and start notification on more than one device at the same time.

Is that possible with bleak?

What I Did

I defined an aync function connect_and_record which connects to a device using the BleakClient by UUID and starts notification with a handler that stores the data in a database.

I tried to run two devices using:

asyncio.gather(connect_and_record(uuid_1), connect_and_record(uuid_2)).

What happens is the first device connects and begins notification, and then the second device connects and it seems to cancel out the first one.

If you have any suggestions I would appreciate it. Thanks.

superfashi commented 4 years ago

I believe this is due to the use of a single manager on mac os, as discussed here #206 Really hope this could get fixed soon.

bsiever commented 4 years ago

@superfashi Can you try PR #209 ? (This is something I tested on my test devices: 2 notifications and 2 indications)

superfashi commented 4 years ago

@bsiever tried and I don't think it solved the problem for running on different threads. Maybe it solved the problem on multiple devices under a single thread, which is what the issue author needed.

Think you might want to take a step ahead and stop using a single CentralManager and try the solution here https://stackoverflow.com/questions/48958267/how-can-i-use-corebluetooth-for-python-without-giving-up-the-main-thread

bsiever commented 4 years ago

The PR does not address the threading issue at all. The PR does allow connection to multiple devices at the same time via multiple client objects, which can be done with a single manager without threads (just doing the normal asycnio bit). (@kswann-imb : The PR #209 may solve your problem)

hbldh commented 4 years ago

My aim is to get the single-thread multi-device solution in #209 working first and then trying to solve #206 during next week. Will get back to you during next week about this.

hbldh commented 4 years ago

I think this will be solved by the merging of PR #227. It will be released later today in version 0.7.0 of bleak.

hbldh commented 4 years ago

Released version 0.7.0 to PyPI just now. It should solve this problem.

kswann-imb commented 4 years ago

Thanks @hbldh

mabhijithn commented 3 years ago

I would like to restart this issue again. I am unable to read notifications from two devices simultaneuously. I am running:

The code I am running is given below based on Issue 345:

import asyncio
from bleak import BleakClient

erc1address = "80:EA:CA:70:00:01"
erc2address = "80:EA:CA:70:00:02"
read_characteristic = '16005991-b131-3396-014c-664c9867b917'

with open('file_one.csv','w') as f:
    f.write("ERC-1\n")

with open('file_two.csv','w') as f:
    f.write("ERC-2\n")

def callback_one(sender, data):
     with open('file_one.csv','a') as f:
         for i in range(len(data)):
             f.write(f'{data[i]}')

def callback_two(sender, data):
     with open('file_two.csv','a') as f:
         for i in range(len(data)):
             f.write(f'{data[i]}')

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

    tasks = asyncio.gather(connect_one(addresses[0]) ,connect_two(addresses[1]))

    loop.run_until_complete(tasks)

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

        print("connect to", address)
        try:
            await client.start_notify(read_characteristic, callback_one)
            while 1:
                await asyncio.sleep(1)
        except Exception as e:
            if e is KeyboardInterrupt:
                await client.stop_notify(read_characteristic)

    print("disconnect from", address)

async def connect_two(address):
    print("starting", address, "loop")
    async with BleakClient(address, timeout=20.0) as client:
        print("connect to", address)
        try:
            await client.start_notify(read_characteristic, callback_two)
            while 1:
                await asyncio.sleep(1)
        except Exception as e:
            if e is KeyboardInterrupt:
                await client.stop_notify(read_characteristic)

    print("disconnect from", address)

if __name__ == "__main__":
    run(
        [erc1address, erc2address]
    )

I have while 1: await sleep(1) because I need to read notifications from both devices. If I replace that with just await sleep(10) for instance, then after 10 seconds, the second connected device notifications are read. However, my devices send notifications continuously, therefore I need to read data from both.

It would be great if any suggestions/help can be provided.