Skip to content

WinRT: pairing crashes if accepting too soon #700

@marianacalzon

Description

@marianacalzon
  • 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'

Metadata

Metadata

Assignees

No one assigned

    Labels

    Backend: WinRTIssues or PRs relating to the WinRT backend

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions