async def read_gatt_char( self, char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID], **kwargs, ) -> bytearray: """Perform read operation on the specified GATT characteristic. Args: char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to read from, specified by either integer handle, UUID or directly by the BleakGATTCharacteristic object representing it. Keyword Args: use_cached (bool): ``False`` forces Windows to read the value from the device again and not use its own cached value. Defaults to ``False``. Returns: (bytearray) The read data. """ use_cached = kwargs.get("use_cached", False) if not isinstance(char_specifier, BleakGATTCharacteristic): characteristic = self.services.get_characteristic(char_specifier) else: characteristic = char_specifier if not characteristic: raise BleakError( "Characteristic {0} was not found!".format(char_specifier)) read_result = await wrap_IAsyncOperation( IAsyncOperation[GattReadResult](characteristic.obj.ReadValueAsync( BluetoothCacheMode. Cached if use_cached else BluetoothCacheMode.Uncached)), return_type=GattReadResult, ) if read_result.Status == GattCommunicationStatus.Success: with BleakDataReader(read_result.Value) as reader: value = bytearray(reader.read()) logger.debug("Read Characteristic {0} : {1}".format( characteristic.uuid, value)) else: if read_result.Status == GattCommunicationStatus.ProtocolError: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X}: {3})" .format( characteristic.uuid, _communication_statues.get(read_result.Status, ""), read_result.ProtocolError, CONTROLLER_ERROR_CODES.get(read_result.ProtocolError, "Unknown"), )) else: raise BleakError( "Could not read characteristic value for {0}: {1}".format( characteristic.uuid, _communication_statues.get(read_result.Status, ""), )) return value
async def write_gatt_char( self, char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID], data: bytearray, response: bool = False, ) -> None: """Perform a write operation of the specified GATT characteristic. Args: char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to write to, specified by either integer handle, UUID or directly by the BleakGATTCharacteristic object representing it. data (bytes or bytearray): The data to send. response (bool): If write-with-response operation should be done. Defaults to `False`. """ if not isinstance(char_specifier, BleakGATTCharacteristic): characteristic = self.services.get_characteristic(char_specifier) else: characteristic = char_specifier if not characteristic: raise BleakError( "Characteristic {} was not found!".format(char_specifier)) with BleakDataWriter(data) as writer: response = (GattWriteOption.WriteWithResponse if response else GattWriteOption.WriteWithoutResponse) write_result = await wrap_IAsyncOperation( IAsyncOperation[GattWriteResult]( characteristic.obj.WriteValueWithResultAsync( writer.detach_buffer(), response)), return_type=GattWriteResult, ) if write_result.Status == GattCommunicationStatus.Success: logger.debug("Write Characteristic {0} : {1}".format( characteristic.uuid, data)) else: if write_result.Status == GattCommunicationStatus.ProtocolError: raise BleakError( "Could not write value {0} to characteristic {1}: {2} (Error: 0x{3:02X}: {4})" .format( data, characteristic.uuid, _communication_statues.get(write_result.Status, ""), write_result.ProtocolError, CONTROLLER_ERROR_CODES.get(write_result.ProtocolError, "Unknown"), )) else: raise BleakError( "Could not write value {0} to characteristic {1}: {2}". format( data, characteristic.uuid, _communication_statues.get(write_result.Status, ""), ))
async def read_gatt_char(self, char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID], **kwargs) -> bytearray: """Perform read operation on the specified GATT characteristic. Args: char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to read from, specified by either integer handle, UUID or directly by the BleakGATTCharacteristic object representing it. Keyword Args: use_cached (bool): ``False`` forces Windows to read the value from the device again and not use its own cached value. Defaults to ``False``. Returns: (bytearray) The read data. """ use_cached = kwargs.get("use_cached", False) if not isinstance(char_specifier, BleakGATTCharacteristic): characteristic = self.services.get_characteristic(char_specifier) else: characteristic = char_specifier if not characteristic: raise BleakError( "Characteristic {0} was not found!".format(char_specifier)) read_result = await characteristic.obj.read_value_async( BluetoothCacheMode.CACHED if use_cached else BluetoothCacheMode. UNCACHED) if read_result.status == GattCommunicationStatus.SUCCESS: value = bytearray( CryptographicBuffer.copy_to_byte_array(read_result.value)) logger.debug("Read Characteristic {0} : {1}".format( characteristic.uuid, value)) else: if read_result.status == GattCommunicationStatus.PROTOCOL_ERROR: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X}: {3})" .format( characteristic.uuid, _communication_statues.get(read_result.status, ""), read_result.protocol_error, CONTROLLER_ERROR_CODES.get(read_result.protocol_error, "Unknown"), )) else: raise BleakError( "Could not read characteristic value for {0}: {1}".format( characteristic.uuid, _communication_statues.get(read_result.status, ""), )) return value
async def read_gatt_descriptor( self, handle: int, use_cached=False, **kwargs ) -> bytearray: """Perform read operation on the specified GATT descriptor. Args: handle (int): The handle of the descriptor to read from. use_cached (bool): `False` forces Windows to read the value from the device again and not use its own cached value. Defaults to `False`. Returns: (bytearray) The read data. """ descriptor = self.services.get_descriptor(handle) if not descriptor: raise BleakError("Descriptor with handle {0} was not found!".format(handle)) read_result = await wrap_IAsyncOperation( IAsyncOperation[GattReadResult]( descriptor.obj.ReadValueAsync( BluetoothCacheMode.Cached if use_cached else BluetoothCacheMode.Uncached ) ), return_type=GattReadResult, ) if read_result.Status == GattCommunicationStatus.Success: with BleakDataReader(read_result.Value) as reader: value = bytearray(reader.read()) logger.debug("Read Descriptor {0} : {1}".format(handle, value)) else: if read_result.Status == GattCommunicationStatus.ProtocolError: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X}: {3})".format( descriptor.uuid, _communication_statues.get(read_result.Status, ""), read_result.ProtocolError, CONTROLLER_ERROR_CODES.get( read_result.ProtocolError, "Unknown" ), ) ) else: raise BleakError( "Could not read Descriptor value for {0}: {1}".format( descriptor.uuid, _communication_statues.get(read_result.Status, ""), ) ) return value
async def write_gatt_char( self, char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID], data: Union[bytes, bytearray, memoryview], response: bool = False, ) -> None: """Perform a write operation of the specified GATT characteristic. Args: char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to write to, specified by either integer handle, UUID or directly by the BleakGATTCharacteristic object representing it. data (bytes or bytearray): The data to send. response (bool): If write-with-response operation should be done. Defaults to `False`. """ if not isinstance(char_specifier, BleakGATTCharacteristic): characteristic = self.services.get_characteristic(char_specifier) else: characteristic = char_specifier if not characteristic: raise BleakError( "Characteristic {} was not found!".format(char_specifier)) response = (GattWriteOption.WRITE_WITH_RESPONSE if response else GattWriteOption.WRITE_WITHOUT_RESPONSE) write_result = await characteristic.obj.write_value_with_result_async( CryptographicBuffer.create_from_byte_array(list(data)), response) if write_result.status == GattCommunicationStatus.SUCCESS: logger.debug("Write Characteristic {0} : {1}".format( characteristic.uuid, data)) else: if write_result.status == GattCommunicationStatus.PROTOCOL_ERROR: raise BleakError( "Could not write value {0} to characteristic {1}: {2} (Error: 0x{3:02X}: {4})" .format( data, characteristic.uuid, _communication_statues.get(write_result.status, ""), write_result.protocol_error, CONTROLLER_ERROR_CODES.get(write_result.protocol_error, "Unknown"), )) else: raise BleakError( "Could not write value {0} to characteristic {1}: {2}". format( data, characteristic.uuid, _communication_statues.get(write_result.status, ""), ))
async def read_gatt_descriptor(self, handle: int, **kwargs) -> bytearray: """Perform read operation on the specified GATT descriptor. Args: handle (int): The handle of the descriptor to read from. Keyword Args: use_cached (bool): `False` forces Windows to read the value from the device again and not use its own cached value. Defaults to `False`. Returns: (bytearray) The read data. """ use_cached = kwargs.get("use_cached", False) descriptor = self.services.get_descriptor(handle) if not descriptor: raise BleakError( "Descriptor with handle {0} was not found!".format(handle)) read_result = await descriptor.obj.read_value_async( BluetoothCacheMode.CACHED if use_cached else BluetoothCacheMode. UNCACHED) if read_result.status == GattCommunicationStatus.SUCCESS: value = bytearray( CryptographicBuffer.copy_to_byte_array(read_result.value)) logger.debug("Read Descriptor {0} : {1}".format(handle, value)) else: if read_result.status == GattCommunicationStatus.PROTOCOL_ERROR: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X}: {3})" .format( descriptor.uuid, _communication_statues.get(read_result.status, ""), read_result.protocol_error, CONTROLLER_ERROR_CODES.get(read_result.protocol_error, "Unknown"), )) else: raise BleakError( "Could not read Descriptor value for {0}: {1}".format( descriptor.uuid, _communication_statues.get(read_result.status, ""), )) return value
async def write_gatt_descriptor( self, handle: int, data: Union[bytes, bytearray, memoryview]) -> None: """Perform a write operation on the specified GATT descriptor. Args: handle (int): The handle of the descriptor to read from. data (bytes or bytearray): The data to send. """ descriptor = self.services.get_descriptor(handle) if not descriptor: raise BleakError( "Descriptor with handle {0} was not found!".format(handle)) with BleakDataWriter(data) as writer: write_result = await wrap_IAsyncOperation( IAsyncOperation[GattWriteResult]( descriptor.obj.WriteValueWithResultAsync( writer.detach_buffer())), return_type=GattWriteResult, ) if write_result.Status == GattCommunicationStatus.Success: logger.debug("Write Descriptor {0} : {1}".format(handle, data)) else: if write_result.Status == GattCommunicationStatus.ProtocolError: raise BleakError( "Could not write value {0} to characteristic {1}: {2} (Error: 0x{3:02X}: {4})" .format( data, descriptor.uuid, _communication_statues.get(write_result.Status, ""), write_result.ProtocolError, CONTROLLER_ERROR_CODES.get(write_result.ProtocolError, "Unknown"), )) else: raise BleakError( "Could not write value {0} to descriptor {1}: {2}".format( data, descriptor.uuid, _communication_statues.get(write_result.Status, ""), ))
async def write_gatt_descriptor( self, handle: int, data: Union[bytes, bytearray, memoryview]) -> None: """Perform a write operation on the specified GATT descriptor. Args: handle (int): The handle of the descriptor to read from. data (bytes or bytearray): The data to send. """ descriptor = self.services.get_descriptor(handle) if not descriptor: raise BleakError( "Descriptor with handle {0} was not found!".format(handle)) write_result = await descriptor.obj.write_value_async( CryptographicBuffer.create_from_byte_array(list(data))) if write_result.status == GattCommunicationStatus.SUCCESS: logger.debug("Write Descriptor {0} : {1}".format(handle, data)) else: if write_result.status == GattCommunicationStatus.PROTOCOL_ERROR: raise BleakError( "Could not write value {0} to characteristic {1}: {2} (Error: 0x{3:02X}: {4})" .format( data, descriptor.uuid, _communication_statues.get(write_result.status, ""), write_result.protocol_error, CONTROLLER_ERROR_CODES.get(write_result.protocol_error, "Unknown"), )) else: raise BleakError( "Could not write value {0} to descriptor {1}: {2}".format( data, descriptor.uuid, _communication_statues.get(write_result.status, ""), ))
async def get_services(self) -> BleakGATTServiceCollection: """Get all services registered for this GATT server. Returns: A :py:class:`bleak.backends.service.BleakGATTServiceCollection` with this device's services tree. """ # Return the Service Collection. if self._services_resolved: return self.services else: logger.debug("Get Services...") services_result = await wrap_IAsyncOperation( IAsyncOperation[GattDeviceServicesResult]( self._requester.GetGattServicesAsync()), return_type=GattDeviceServicesResult, ) if services_result.Status != GattCommunicationStatus.Success: if services_result.Status == GattCommunicationStatus.ProtocolError: raise BleakDotNetTaskError( "Could not get GATT services: {0} (Error: 0x{1:02X}: {2})" .format( _communication_statues.get(services_result.Status, ""), services_result.ProtocolError, CONTROLLER_ERROR_CODES.get( services_result.ProtocolError, "Unknown"), )) else: raise BleakDotNetTaskError( "Could not get GATT services: {0}".format( _communication_statues.get(services_result.Status, ""))) for service in services_result.Services: characteristics_result = await wrap_IAsyncOperation( IAsyncOperation[GattCharacteristicsResult]( service.GetCharacteristicsAsync()), return_type=GattCharacteristicsResult, ) self.services.add_service(BleakGATTServiceDotNet(service)) if characteristics_result.Status != GattCommunicationStatus.Success: if (characteristics_result.Status == GattCommunicationStatus.ProtocolError): raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X}: {3})" .format( service, _communication_statues.get( characteristics_result.Status, ""), characteristics_result.ProtocolError, CONTROLLER_ERROR_CODES.get( characteristics_result.ProtocolError, "Unknown"), )) else: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1}". format( service, _communication_statues.get( characteristics_result.Status, ""), )) for characteristic in characteristics_result.Characteristics: descriptors_result = await wrap_IAsyncOperation( IAsyncOperation[GattDescriptorsResult]( characteristic.GetDescriptorsAsync()), return_type=GattDescriptorsResult, ) self.services.add_characteristic( BleakGATTCharacteristicDotNet(characteristic)) if descriptors_result.Status != GattCommunicationStatus.Success: if (characteristics_result.Status == GattCommunicationStatus.ProtocolError): raise BleakDotNetTaskError( "Could not get GATT descriptors for {0}: {1} (Error: 0x{2:02X}: {3})" .format( service, _communication_statues.get( descriptors_result.Status, ""), descriptors_result.ProtocolError, CONTROLLER_ERROR_CODES.get( descriptors_result.ProtocolError, "Unknown"), )) else: raise BleakDotNetTaskError( "Could not get GATT descriptors for {0}: {1}". format( characteristic, _communication_statues.get( descriptors_result.Status, ""), )) for descriptor in list(descriptors_result.Descriptors): self.services.add_descriptor( BleakGATTDescriptorDotNet( descriptor, characteristic.Uuid.ToString(), int(characteristic.AttributeHandle), )) logger.info("Services resolved for %s", str(self)) self._services_resolved = True return self.services
async def get_services(self, **kwargs) -> BleakGATTServiceCollection: """Get all services registered for this GATT server. Keyword Args: use_cached (bool): If set to `True`, then the OS level BLE cache is used for getting services, characteristics and descriptors. Returns: A :py:class:`bleak.backends.service.BleakGATTServiceCollection` with this device's services tree. """ use_cached = kwargs.get("use_cached", self._use_cached) # Return the Service Collection. if self._services_resolved: return self.services else: logger.debug("Get Services...") services_result = await self._requester.get_gatt_services_async( BluetoothCacheMode. CACHED if use_cached else BluetoothCacheMode.UNCACHED) if services_result.status != GattCommunicationStatus.SUCCESS: if services_result.status == GattCommunicationStatus.PROTOCOL_ERROR: raise BleakDotNetTaskError( "Could not get GATT services: {0} (Error: 0x{1:02X}: {2})" .format( _communication_statues.get(services_result.status, ""), services_result.protocol_error, CONTROLLER_ERROR_CODES.get( services_result.protocol_error, "Unknown"), )) else: raise BleakDotNetTaskError( "Could not get GATT services: {0}".format( _communication_statues.get(services_result.status, ""))) for service in services_result.services: characteristics_result = await service.get_characteristics_async( BluetoothCacheMode. CACHED if use_cached else BluetoothCacheMode.UNCACHED) self.services.add_service(BleakGATTServiceWinRT(service)) if characteristics_result.status != GattCommunicationStatus.SUCCESS: if (characteristics_result.status == GattCommunicationStatus.PROTOCOL_ERROR): raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X}: {3})" .format( service, _communication_statues.get( characteristics_result.status, ""), characteristics_result.protocol_error, CONTROLLER_ERROR_CODES.get( characteristics_result.protocol_error, "Unknown"), )) else: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1}". format( service, _communication_statues.get( characteristics_result.status, ""), )) for characteristic in characteristics_result.characteristics: descriptors_result = await characteristic.get_descriptors_async( BluetoothCacheMode. CACHED if use_cached else BluetoothCacheMode.UNCACHED) self.services.add_characteristic( BleakGATTCharacteristicWinRT(characteristic)) if descriptors_result.status != GattCommunicationStatus.SUCCESS: if (characteristics_result.status == GattCommunicationStatus.PROTOCOL_ERROR): raise BleakDotNetTaskError( "Could not get GATT descriptors for {0}: {1} (Error: 0x{2:02X}: {3})" .format( service, _communication_statues.get( descriptors_result.status, ""), descriptors_result.protocol_error, CONTROLLER_ERROR_CODES.get( descriptors_result.protocol_error, "Unknown"), )) else: raise BleakDotNetTaskError( "Could not get GATT descriptors for {0}: {1}". format( characteristic, _communication_statues.get( descriptors_result.status, ""), )) for descriptor in list(descriptors_result.descriptors): self.services.add_descriptor( BleakGATTDescriptorWinRT( descriptor, str(characteristic.uuid), characteristic.attribute_handle, )) logger.info("Services resolved for %s", str(self)) self._services_resolved = True return self.services