Example #1
0
    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
Example #2
0
    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, ""),
                    ))
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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, ""),
                    ))
Example #6
0
    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
Example #7
0
    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, ""),
                    ))
Example #8
0
    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, ""),
                    ))
Example #9
0
    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
Example #10
0
    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