diff --git a/bumble/att.py b/bumble/att.py index 2a15f00..0e1d493 100644 --- a/bumble/att.py +++ b/bumble/att.py @@ -23,11 +23,12 @@ # Imports # ----------------------------------------------------------------------------- from __future__ import annotations +import functools import struct from pyee import EventEmitter from typing import Dict, Type, TYPE_CHECKING -from bumble.core import UUID, name_or_number +from bumble.core import UUID, name_or_number, get_dict_key_by_value from bumble.hci import HCI_Object, key_with_value from bumble.colors import color @@ -725,11 +726,33 @@ class Attribute(EventEmitter): READ_REQUIRES_AUTHORIZATION = 0x40 WRITE_REQUIRES_AUTHORIZATION = 0x80 + PERMISSION_NAMES = { + READABLE: 'READABLE', + WRITEABLE: 'WRITEABLE', + READ_REQUIRES_ENCRYPTION: 'READ_REQUIRES_ENCRYPTION', + WRITE_REQUIRES_ENCRYPTION: 'WRITE_REQUIRES_ENCRYPTION', + READ_REQUIRES_AUTHENTICATION: 'READ_REQUIRES_AUTHENTICATION', + WRITE_REQUIRES_AUTHENTICATION: 'WRITE_REQUIRES_AUTHENTICATION', + READ_REQUIRES_AUTHORIZATION: 'READ_REQUIRES_AUTHORIZATION', + WRITE_REQUIRES_AUTHORIZATION: 'WRITE_REQUIRES_AUTHORIZATION', + } + + @staticmethod + def string_to_permissions(permissions_str: str): + return functools.reduce( + lambda x, y: x | get_dict_key_by_value(Attribute.PERMISSION_NAMES, y), + permissions_str.split(","), + 0, + ) + def __init__(self, attribute_type, permissions, value=b''): EventEmitter.__init__(self) self.handle = 0 self.end_group_handle = 0 - self.permissions = permissions + if isinstance(permissions, str): + self.permissions = self.string_to_permissions(permissions) + else: + self.permissions = permissions # Convert the type to a UUID object if it isn't already if isinstance(attribute_type, str): diff --git a/bumble/device.py b/bumble/device.py index ca2a9bf..51bbb28 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -1008,7 +1008,7 @@ class Device(CompositeEventEmitter): new_characteristic = Characteristic( uuid=characteristic["uuid"], properties=characteristic["properties"], - permissions=int(characteristic["permissions"], 0), + permissions=characteristic["permissions"], descriptors=descriptors, ) characteristics.append(new_characteristic) diff --git a/tests/gatt_test.py b/tests/gatt_test.py index 2473623..70bbdb8 100644 --- a/tests/gatt_test.py +++ b/tests/gatt_test.py @@ -37,10 +37,12 @@ from bumble.gatt import ( Service, Characteristic, CharacteristicValue, + Descriptor, ) from bumble.transport import AsyncPipeSink from bumble.core import UUID from bumble.att import ( + Attribute, ATT_EXCHANGE_MTU_REQUEST, ATT_ATTRIBUTE_NOT_FOUND_ERROR, ATT_PDU, @@ -861,6 +863,29 @@ async def async_main(): await test_mtu_exchange() +# ----------------------------------------------------------------------------- +def test_attribute_string_to_permissions(): + assert Attribute.string_to_permissions('READABLE') == 1 + assert Attribute.string_to_permissions('WRITEABLE') == 2 + assert Attribute.string_to_permissions('READABLE,WRITEABLE') == 3 + + +# ----------------------------------------------------------------------------- +def test_charracteristic_permissions(): + characteristic = Characteristic( + 'FDB159DB-036C-49E3-B3DB-6325AC750806', + Characteristic.READ | Characteristic.WRITE | Characteristic.NOTIFY, + 'READABLE,WRITEABLE', + ) + assert characteristic.permissions == 3 + + +# ----------------------------------------------------------------------------- +def test_descriptor_permissions(): + descriptor = Descriptor('2902', 'READABLE,WRITEABLE') + assert descriptor.permissions == 3 + + # ----------------------------------------------------------------------------- if __name__ == '__main__': logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())