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

client.write_gatt_char() not exposing GATT error code to user #174

Closed
Matt-Hicks-Bose opened this issue Mar 27, 2020 · 9 comments
Closed
Assignees
Labels
Backend: pythonnet Issues or PRs relating to the .NET/pythonnet backend enhancement New feature or request
Milestone

Comments

@Matt-Hicks-Bose
Copy link

  • bleak version: 0.6.1
  • Python version: 3.7.6
  • Operating System: Windows 10.0.18363
  • BlueZ version (bluetoothctl -v) in case of Linux: N/A

Description

I am working with a BLE device that will return an application specific ATT error response (between 0x80 - 0x9F, as required by the Bluetooth specification) when a characteristic is written with invalid data. I am writing to this characteristic with client.write_gatt_char() and specifying response=True. However, when I run this code with intentionally invalid data, I am getting a BleakError without the ATT error response, because of this I cannot handle the error in my own code correctly.

What I Did

import asyncio
import bleak

DEVICE_MAC = '<my device mac address>' # Change this to your MAC address
CONFIG_UUID = '<my characteristic UUID>' # Change this to your characteristic UUID

async def run():
    # Connect to client and wait for connection to complete
    client = bleak.BleakClient(DEVICE_MAC, timeout=10)
    await client.connect()

    # Characteristic before it is set
    print(f'Before: {await client.read_gatt_char(CONFIG_UUID)}')

    # Set a good config
    good_data = b'\x00\x11\x40' # good config
    await client.write_gatt_char(CONFIG_UUID, good_data, True)

    # Characteristic after it is set
    print(f'After good: {await client.read_gatt_char(CONFIG_UUID)}')

    # Set to a known bad config
    bad_data = b'\x90\x11\x40' # intentionally bad config
    await client.write_gatt_char(CONFIG_UUID, bad_data, True)

    # This will never run due to error
    print(f'After bad: {await client.read_gatt_char(CONFIG_UUID)}')

if __name__ == "__main__":
    # Run the program
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())  

When I run this my output looks like:

Before: bytearray(b'\x00\x00\x00')
After good: bytearray(b'\x00\x11@')
<traceback snipped>
bleak.exc.BleakError: Could not write value b'\x90\x11@' to characteristic <my characteristic UUID>: 2

It is expected that an ATT error response would be returned or raised, but the python error raised does not indicate what the ATT error response was.

Further investigation

I looked through the .NET documentation that was mentioned in #59 ( https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.genericattributeprofile.gattwriteresult ), and it looks like the ATT error response is contained in the ProtocolError property of the gattwriteresult object. On my local copy of the library I changed the BleakError raised in write_gatt_char(), part of the dotNET backend from:

raise BleakError(
    "Could not write value {0} to characteristic {1}: {2}".format(
        data, characteristic.uuid, write_result.Status
    )
)

To:

raise BleakError(
    "Could not write value {0} to characteristic {1}    Status: {2}    ProtocolError: 0x{3:02X}".format(
        data, characteristic.uuid, write_result.Status, write_result.ProtocolError
    )
)

This now results in an error that shows the expected ATT error response 0x90 which in this application means "invalid configuration requested":

bleak.exc.BleakError: Could not write value b'\x90\x01@' to characteristic <my characteristic UUID>    Status: 2    ProtocolError: 0x90

Is it possible to expose this ATT Error Response to the user of the library? Either through a seperate error message that could be caught and handled, a return value, or some other mechanism?

@hbldh
Copy link
Owner

hbldh commented Mar 27, 2020

It will not be done in the foreseeable future I am afraid. I am swamped with other (paid) work and cannot guarantee doing anything with this project for quite some time. I will still address PRs to develop branch occasionally, so if you desire these changes you have to do the legwork yourselves.

@hbldh hbldh self-assigned this Mar 27, 2020
@hbldh hbldh added the Backend: BlueZ Issues and PRs relating to the BlueZ backend label Mar 27, 2020
@hbldh hbldh added Backend: pythonnet Issues or PRs relating to the .NET/pythonnet backend and removed Backend: BlueZ Issues and PRs relating to the BlueZ backend labels Jun 2, 2020
@hbldh hbldh added this to the Version 0.7.0 milestone Jun 2, 2020
@hbldh
Copy link
Owner

hbldh commented Jun 2, 2020

This is a very good suggestion. Implemented a version of this (2cf7b8b) on the develop branch. It will be included in version 0.7.0 of bleak. Thank you!

@hbldh hbldh added the enhancement New feature or request label Jun 2, 2020
@Matt-Hicks-Bose
Copy link
Author

Excellent! Will this be implemented in the two other backends as well?

@hbldh
Copy link
Owner

hbldh commented Jun 3, 2020

Right now, no. I am not sure where to fetch that information in BlueZ nor in Core Bluetooth. Bleak is very much a “each one to one’s own” in the sense that if you ask for it and do most of the actual detective work of the development, I will probably integrate it. If someone needs it, they are free to go look for it and I will eventually try to merge their OR or in this case request.

On that note, please try out the dev branch and see if you can reproduce the errors and verify the solution!

@hbldh hbldh modified the milestones: Version 0.7.0, Version 0.7.X Jun 30, 2020
@hbldh hbldh mentioned this issue Jun 30, 2020
@hbldh
Copy link
Owner

hbldh commented Jul 9, 2020

@Matt-Hicks-Bose These error codes, where did you find specifications of them? Another user got a 0x0ferror code in #249 and I cannot find any reference to them...

@hbldh hbldh modified the milestones: Version 0.7.X, Version 0.8.0 Jul 9, 2020
@Matt-Hicks-Bose
Copy link
Author

Matt-Hicks-Bose commented Jul 9, 2020

The error codes used by GATT are defined in the Bluetooth Core Specification (Version 5.2, Vol 3, Part H, Section 3.4.1.1, Table 3.4 (pp. 1491)), which is available to download here: https://www.bluetooth.com/specifications/bluetooth-core-specification/

I will add a comment to the other issue with more details about the error code.

@hbldh
Copy link
Owner

hbldh commented Jul 16, 2020

@Matt-Hicks-Bose Thank you! I will try to include those error codes in bleak for future use.

@hbldh
Copy link
Owner

hbldh commented Jul 20, 2020

Added text strings of these errors codes in 37597b3 and showing these when raising Protocol Errors. Thank you @Matt-Hicks-Bose; it will be included in version 0.8.0, after which I will close this issue and open two new ones for BlueZ and Core Bluetooth backends. It would be nice to provide the same details there, but I am not sure it is possible.

@hbldh
Copy link
Owner

hbldh commented Sep 25, 2020

Will close for now. I have had no success finding GATT error codes in BlueZ or Core Bluetooth.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: pythonnet Issues or PRs relating to the .NET/pythonnet backend enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants