hbldh / bleak

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

bleak.exc.BleakError: Could not pair with device: 19: FAILED #789

Open ghazijallouli opened 2 years ago

ghazijallouli commented 2 years ago

Description

there is a GATT server defined in STM32WB55RG i want to connect to a stm32WB55RG via ble and read values from characteristics (to read the values you have to bond with the device)

What I Did

i wrote the script below and i tried all level of authentication but the error still the same

import asyncio
import sys
from asyncore import loop

from bleak import BleakScanner, BleakClient

deviceName = "ETO"

global scanned_device

async def findaddress():
    found = False
    tentative = 1
    while not found:
        devices = await BleakScanner.discover(timeout=8)
        i = 0
        for d in devices:
            i = i + 1
            print("device {0} name is  '{1}'".format(i, d.name))

            if (d.name is not None) and (d.name == deviceName):
                scanned_device = d
                found = True
        if not found:
            print("device not found in tentative  {0} \n\n ".format(tentative))
            tentative = tentative + 1

    return scanned_device.address

ADDRESS = asyncio.run(findaddress())

async def main(address: str):
    client = BleakClient(address, loop=loop)
    print("g")
    await client.connect()
    print("gjm")
    await client.unpair()
    print("gj")

    await client.pair(3)
    print("ma taadech")
    svcs = await client.get_services()
    for service in svcs:
        print("\tService: {0}".format(service))
        for char in service.characteristics:
            print("\t\tcharacteristic:")
            print(char)
            print(char.description)
            print(char.properties)
            if "read" in char.properties:
                try:
                    value = bytes(await client.read_gatt_char(char))
                    print(" value of read charac '{0}'".format(value))
                except:
                    print("not enough authentication")

if __name__ == "__main__":
    asyncio.run(main(ADDRESS))
dlech commented 2 years ago

bleak version: Latest Python version: Latest

Latest is ambiguous since it can change when there is a new release. What are the exact version numbers?

dlech commented 2 years ago

Can you give the full stack trace of the crash? Have you tried following the troubleshooting tips in the docs?

ghazijallouli commented 2 years ago
Traceback (most recent call last):
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\ETO.py", line 60, in <module>
Exception ignored in:     <function BleakClientWinRT.connect.<locals>.session_status_changed_event_handler at 0x000001F9C81990D0>
Traceback (most recent call last):
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\testble\lib\site-packages\bleak\backends\winrt\client.py", line 241, in session_status_changed_event_handler
asyncio.run(main(ADDRESS))
  File "C:\Users\gjallouli\AppData\Local\Programs\Python\Python39\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Users\gjallouli\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 642, in run_until_complete
    loop.call_soon_threadsafe(handle_session_status_changed, args)
  File "C:\Users\gjallouli\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 791, in call_soon_threadsafe
        return future.result()self._check_closed()
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\ETO.py", line 39, in main

  File "C:\Users\gjallouli\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 510, in _check_closed
    paired = await client.pair(protection_level=2)
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\testble\lib\site-packages\bleak\backends\winrt\client.py", line 384, in pair
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
    raise BleakError(
bleak.exc.BleakError: Could not pair with device: 19: FAILED
ghazijallouli commented 2 years ago

bleak version: 0.14.2 python version: 3.9

dlech commented 2 years ago

RuntimeError: Event loop is closed

It think the problem is that your program uses two different run loops.


ADDRESS = asyncio.run(findaddress())

if __name__ == "__main__":
    asyncio.run(main(ADDRESS))

Try rewriting the program to only use one run loop.

ghazijallouli commented 2 years ago

this is what i get after rewriting the program using one run loop, the problem is not there because the connexion is ensured even with two different run loops but pairing is not even after using one run loop

Traceback (most recent call last):
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\ETO.py", line 61, in <module>
    asyncio.run(main())
  File "C:\Users\gjallouli\AppData\Local\Programs\Python\Python39\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Users\gjallouli\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 642, in run_until_complete
    return future.result()
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\ETO.py", line 40, in main
    paired = await client.pair(protection_level=0)
  File "C:\Users\gjallouli\PycharmProjects\pythonProject\testble\lib\site-packages\bleak\backends\winrt\client.py", line 384, in pair
    raise BleakError(
bleak.exc.BleakError: Could not pair with device: 19: FAILED
dlech commented 2 years ago

A quick web search of this error gives: https://docs.microsoft.com/en-us/answers/questions/36820/bluetoothledevice-pairasync-intermittantly-fails.html

So I would suggested doing a Bluetooth packet capture as detailed in the Bleak troubleshooting docs.

ghazijallouli commented 2 years ago

after some research i think the option pairing is available only when you work with linux because it requires BlueZ and it's available only in linux

QuadCorei8085 commented 1 year ago

Having the same issue.

When a phone issues the pairing request I see it uses the IO capability 0x04 image and the request is accepted by the STM32 board

When doing it with bleak (windows 10): image

and the request is rejected by the STM32 board (reasoncode = 0x03 auth requirements): image

from ble spec: image

Where/how can i set that iocapability in winrt?

QuadCorei8085 commented 1 year ago

Okay even after changing the ceremony in winrt\client.py to: ceremony = DevicePairingKinds.PROVIDE_PIN | DevicePairingKinds.DISPLAY_PIN

I get the same error. Now the only difference is the LTK key field is not present from BLEAK: image

dlech commented 1 year ago

Thanks for the detailed analysis. FYI, there is some work-in-progress improvements in #1100 that will effectively allow selecting the DevicePairingKinds. However, I'm not aware of a way to affect the Encryption Key bit.

QuadCorei8085 commented 1 year ago

Alright. In the meantime I switched off the MITM attack detection on the embedded stm32 side and it works with pairing mode "ceremony = DevicePairingKinds.CONFIRM_ONLY" only. When I set any other pairing mode the pairing fails with error code 0x0c (numeric comparision failed). I guess this is reasonable given there is no way to present/confirm the pin on python side at the moment.

For STM32WB55 users

define CFG_MITM_PROTECTION CFG_MITM_PROTECTION_NOT_REQUIRED

dlech commented 1 year ago

You could also try passing protection_level to see if it makes a difference.