Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WinRT: pairing crashes if accepting too soon #700

Open
marianacalzon opened this issue Dec 27, 2021 · 2 comments
Open

WinRT: pairing crashes if accepting too soon #700

marianacalzon opened this issue Dec 27, 2021 · 2 comments
Labels
Backend: WinRT Issues or PRs relating to the WinRT backend

Comments

@marianacalzon
Copy link

marianacalzon commented Dec 27, 2021

  • bleak version: 0.13.0
  • Python version: 3.8.2
  • Operating System: Windows 10

Description

Trying to pair and connect to the device, after accepting to pair on the OS pop-up, Bleak fails.
The device I am trying to connect to requires pairing.
If I accept pairing as soon as it pops up, the script fails. If I wait until after services discovery has finished, and only then accept the pairing, it will work OK.

What I Did

With this code:

#  bleak_minimal_example.py
import asyncio
from bleak import BleakScanner
from bleak import BleakClient


address = "AA:AA:AA:AA:AA:AA"
# Characteristics UUIDs
NUM_SENSORS_UUID = "b9e634a8-57ef-11e9-8647-d663bd873d93"

# ===============================================================
# Connect and read
# ===============================================================
async def run_connection(address, debug=False):

    async with BleakClient(address) as client:
    
        print("  >>  Please accept pairing")
        await asyncio.sleep(5.0)
        
        print("  >>  Reading...")
        num_sensors = await client.read_gatt_char(NUM_SENSORS_UUID, use_cached = True)
        print(" Number of sensors: {0}".format(num_sensors.hex()))
      

# ===============================================================
#    MAIN
# ===============================================================
if __name__ == "__main__":


    loop = asyncio.get_event_loop()
    loop.run_until_complete(run_connection(address))
    
    print ('>> Goodbye!')
    exit(0)

Use case 1: fails
Accepting the pairing before it finished discovering services - fails

  1. the script calls BleakClient.connect()
  2. connects to the device and Windows pop-up requests to pair
  3. Bleak.connect() is still doing the discovery (and it takes long, because the device has many services with many chars.)
  4. if I accept the pairing before it finished discovering it fails 

The traceback of the error:

Traceback (most recent call last):
  File "bleak_minimal_example.py", line 86, in <module>
    loop.run_until_complete(run_connection(device_address))
  File "C:\Program Files\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "bleak_minimal_example.py", line 50, in run_connection
    async with BleakClient(address) as client:
  File "C:\Program Files\Python38\lib\site-packages\bleak\backends\client.py", line 61, in __aenter__
    await self.connect()
  File "C:\Program Files\Python38\lib\site-packages\bleak\backends\winrt\client.py", line 258, in connect
    await self.get_services()
  File "C:\Program Files\Python38\lib\site-packages\bleak\backends\winrt\client.py", line 446, in get_services
    await service.get_characteristics_async(
OSError: [WinError -2147418113] Catastrophic failure

Use case 2: succeeds
Waiting to accept pairing, then succeeds

  1. the script calls BleakClient.connect()
  2. connects to the device and Windows pop-up requests to pair
  3. Bleak.connect() is still doing the discovery (and it takes long, because the device has many services with many chars.)
  4. after connect returned I print ('Please accept pairing')
  5. I accept the pairing
  6. the script reads + writes... all good

Alternative use of the API:

With the script modified to call pair() before connect():

#  bleak_minimal_pair_example.py
import asyncio
from bleak import BleakScanner
from bleak import BleakClient

address = "AA:AA:AA:AA:AA:AA"
# Characteristics UUIDs
NUM_SENSORS_UUID = "b9e634a8-57ef-11e9-8647-d663bd873d93"


# ===============================================================
# Connect and read
# ===============================================================
async def run_connection(address, debug=False):

    client = BleakClient(address)

    if await client.pair():
        pritnt("paired")

    await client.connect()
    
    print("  >>  Reading...")
    num_sensors = await client.read_gatt_char(NUM_SENSORS_UUID, use_cached = True)
    print(" Number of sensors: {0}".format(num_sensors.hex()))
      

# ===============================================================
#    MAIN
# ===============================================================
if __name__ == "__main__":
   
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run_connection(address))

    print ('>> Goodbye!')
    exit(0)

The execution fails as follows:

The traceback of the error:

python bleak_minimal_pair_example.py
Traceback (most recent call last):
  File "bleak_minimal_pair_example.py", line 47, in <module>
    loop.run_until_complete(run_connection(address))
  File "C:\Program Files\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "bleak_minimal_pair_example.py", line 31, in run_connection
    if await client.pair():
  File "C:\Program Files\Python38\lib\site-packages\bleak\backends\winrt\client.py", line 336, in pair
    self._requester.device_information.pairing.can_pair
AttributeError: 'NoneType' object has no attribute 'device_information'
@dlech dlech added the Backend: WinRT Issues or PRs relating to the WinRT backend label Dec 27, 2021
@dlech
Copy link
Collaborator

dlech commented Dec 28, 2021

OSError: [WinError -2147418113] Catastrophic failure

Unfortunately, this means the error comes from the OS and there probably isn't a way to fix it in Bleak.

There is #640 that would allow implementing the pairing in Python instead of using the OS dialog, but it needs some more work.

Logging Bluetooth packets might also offer more insight in to what Windows is actually doing.

@bojanpotocnik
Copy link
Contributor

bojanpotocnik commented Nov 22, 2022

@marianacalzon can you perhaps try again using test pairing branch

pip install --force-reinstall git+https://github.com/bojanpotocnik/bleak@pairing_no_service_discovery

and using

    client = BleakClient(address, skip_service_discovery=True)

as described here https://github.com/bojanpotocnik/bleak/blob/cfd09baddfbd27538e9a1cdd2ef3c7b8f2af229c/examples/pairing_agent.py#L82-L88 (from #1133)? Based on my tests, this should solve your issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: WinRT Issues or PRs relating to the WinRT backend
Projects
None yet
Development

No branches or pull requests

3 participants