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

Bluetooth Short UUIDs are not resolving correctly #1498

Closed
StephenDone opened this issue Jan 30, 2024 · 2 comments · Fixed by #1551
Closed

Bluetooth Short UUIDs are not resolving correctly #1498

StephenDone opened this issue Jan 30, 2024 · 2 comments · Fixed by #1551
Labels
bug Something isn't working

Comments

@StephenDone
Copy link

  • bleak version: 0.21.1
  • Python version: Python 3.11.2
  • Operating System: Debian GNU/Linux 12 (bookworm)
  • BlueZ version (bluetoothctl -v) in case of Linux: bluetoothctl: 5.66
  • Raspberry PI 4B.

Description

After installing bleak, I tried the basic 'USAGE' sample from here: https://github.com/hbldh/bleak
...which reads the model number characteristic. Since my device does not have this characteristic, I changed to the Manufacturer Name UUID - "2A29", instead of "2A24". With no other changes, the sample fails with error 'Characteristic with UUID 2A29 could not be found.

What I Did

I experimented with using the characteristic, the characteristic handle, short integer uuid, short string uuid and full uuid. The characteristic, characteristic handle and full uuid all returned the manufacturer name. Both short uuids tests did not.

Test Program

import asyncio
from bleak import BleakClient
from bleak import BleakScanner

async def main():
    print("Scanning for device...")
    bledevice = await BleakScanner.find_device_by_name("Train.Red FYER 0220")

    if bledevice == None: 
        print("Device not found")
        exit
    else:
        print("Device found.")

    print("Connecting to device...")
    client = BleakClient(bledevice)
    try:
        await client.connect()
        print(f"Connected={client.is_connected}")
        print(f"Address={client.address}")

        ManChar = None

        for handle in client.services.services:
            service = client.services.services[handle]
            print(handle, service.uuid, service.description)

            for characteristic in service.characteristics:
                print(f"   {characteristic.handle} {characteristic.uuid} {characteristic.description}")
                if(characteristic.uuid=='00002a29-0000-1000-8000-00805f9b34fb'):
                    print('   (Found Manufacturer Characteristic)')
                    ManChar=characteristic

                for descriptor in characteristic.descriptors:
                    print(f"      {descriptor.handle} {descriptor.uuid} {descriptor.description}")

        if(ManChar==None): exit

        # This works
        print(f"read_gatt_char({ManChar}):")
        try:
            manufacturer_name = await client.read_gatt_char(ManChar)
            print("  {0}".format("".join(map(chr, manufacturer_name))))
        except Exception as e:
            print(f"  {e}")

        # This works
        print(f"read_gatt_char({ManChar.handle}):")
        try:
            manufacturer_name = await client.read_gatt_char(ManChar.handle)
            print("  {0}".format("".join(map(chr, manufacturer_name))))
        except Exception as e:
            print(f"  {e}")

        # This works
        print("read_gatt_char('00002a29-0000-1000-8000-00805f9b34fb'):")
        try:
            manufacturer_name = await client.read_gatt_char('00002a29-0000-1000-8000-00805f9b34fb')
            print("  {0}".format("".join(map(chr, manufacturer_name))))
        except Exception as e:
            print(f"  {e}")

        # This fails
        print("read_gatt_char(0x2A29):")
        try:
            manufacturer_name = await client.read_gatt_char(0x2A29)
            print("  {0}".format("".join(map(chr, manufacturer_name))))
        except Exception as e:
            print(f"  {e}")

        # This fails
        print("read_gatt_char('2A29'):")
        try:
            manufacturer_name = await client.read_gatt_char('2A29')
            print("  {0}".format("".join(map(chr, manufacturer_name))))
        except Exception as e:
            print(f"  {e}")

        # This fails
        print("read_gatt_char('2a29'):")
        try:
            manufacturer_name = await client.read_gatt_char('2a29')
            print("  {0}".format("".join(map(chr, manufacturer_name))))
        except Exception as e:
            print(f"  {e}")

    finally:
        await client.disconnect()

asyncio.run(main())

Test Output

Scanning for device...
Device found.
Connecting to device...
Connected=True
Address=CB:93:EC:D1:C2:2D
20 0000180f-0000-1000-8000-00805f9b34fb Battery Service
   21 00002a19-0000-1000-8000-00805f9b34fb Battery Level
10 00001801-0000-1000-8000-00805f9b34fb Generic Attribute Profile
   11 00002a05-0000-1000-8000-00805f9b34fb Service Changed
      13 00002902-0000-1000-8000-00805f9b34fb Client Characteristic Configuration
32 00004400-12df-4fbd-b4cd-a4471afe3d11 Unknown
   33 00004401-12df-4fbd-b4cd-a4471afe3d11 Unknown
      35 00002902-0000-1000-8000-00805f9b34fb Client Characteristic Configuration
   36 00004402-12df-4fbd-b4cd-a4471afe3d11 Unknown
14 00002200-d578-4741-9b5b-7c64e958cfc6 Unknown
   15 00002201-d578-4741-9b5b-7c64e958cfc6 Unknown
      17 00002902-0000-1000-8000-00805f9b34fb Client Characteristic Configuration
   18 00002202-d578-4741-9b5b-7c64e958cfc6 Unknown
23 0000180a-0000-1000-8000-00805f9b34fb Device Information
   24 00002a29-0000-1000-8000-00805f9b34fb Manufacturer Name String
   (Found Manufacturer Characteristic)
   26 00002a24-0000-1000-8000-00805f9b34fb Model Number String
   30 00002a26-0000-1000-8000-00805f9b34fb Firmware Revision String
   28 00002a27-0000-1000-8000-00805f9b34fb Hardware Revision String
read_gatt_char(00002a29-0000-1000-8000-00805f9b34fb (Handle: 24): Manufacturer Name String):
  Train.Red
read_gatt_char(24):
  Train.Red
read_gatt_char('00002a29-0000-1000-8000-00805f9b34fb'):
  Train.Red
read_gatt_char(0x2A29):
  Characteristic with UUID 10793 could not be found!
read_gatt_char('2A29'):
  Characteristic with UUID 2A29 could not be found!
read_gatt_char('2a29'):
  Characteristic with UUID 2a29 could not be found!
@dlech
Copy link
Collaborator

dlech commented Jan 31, 2024

read_gatt_char(0x2A29):
Characteristic with UUID 10793 could not be found!

This is expected since int values are treated as a "handle" rather than a UUID.

The "correct" way to do this would be read_gatt_char(normalize_uuid_16(0x2A29)) which converts it to the full UUID string.

read_gatt_char('2A29'):
Characteristic with UUID 2A29 could not be found!
read_gatt_char('2a29'):
Characteristic with UUID 2a29 could not be found!

This looks like it could potentially be a bug/inconsistency in the APIs. Workaround could be to use the normalize_uuid_16() variant mentioned above.

@dlech dlech added the bug Something isn't working label Jan 31, 2024
@StephenDone
Copy link
Author

Ok, no problem. And thanks for writing and sharing this excellent ble client.

May I suggest updating the usage example code, so that it works though. It may discourage some people if they can’t get the example to work. Maybe add the function you suggest, or use the full guid.

dlech added a commit that referenced this issue Apr 29, 2024
This fixes 4-character UUIDs causing BleakCharacteristicNotFoundError
instead of being properly resolved.

Fixes: #1498
dlech added a commit that referenced this issue Apr 29, 2024
This fixes 4-character UUIDs causing BleakCharacteristicNotFoundError
instead of being properly resolved.

Fixes: #1498
@dlech dlech mentioned this issue May 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants