Exemple #1
0
    def notify(
        self, data
    ) -> IdBasedEventWaitable[GattsCharacteristic,
                              NotificationCompleteEventArgs]:
        """
        Notifies the client with the data provided without setting the data into the characteristic value.
        If data is not provided (None), will notify with the currently-set value of the characteristic

        :param data: Optional data to notify the client with. If supplied, must be an iterable type such as a
                     str, bytes, or list of uint8 values, or a BleDataStream object.
                     Length must be less than or equal to the characteristic's max length.
                     If a string is given, it will be encoded using the string_encoding property of the characteristic.
        :raises: InvalidStateException if the client is not subscribed to the characteristic
        :raises: InvalidOperationException if the characteristic is not configured for notifications/indications
        :return: An EventWaitable that will trigger when the notification is successfully sent to the client. The waitable
                 also contains the ID of the sent notification which is used in the on_notify_complete event
        """
        if isinstance(data, BleDataStream):
            value = data.value
        if isinstance(data, str):
            value = data.encode(self.string_encoding)
        if not self.notifiable:
            raise InvalidOperationException(
                "Cannot notify client. "
                "{} not set up for notifications or indications".format(
                    self.uuid))
        if not self.client_subscribed:
            raise InvalidStateException(
                "Client is not subscribed, cannot notify client")

        notification_id = self._notification_manager.notify(
            self, self._value_attr.handle, self._on_notify_complete, data)
        return IdBasedEventWaitable(self._on_notify_complete, notification_id)
Exemple #2
0
    def subscribe(self, on_notification_handler, prefer_indications=False):
        """
        Subscribes to the characteristic's indications or notifications, depending on what's available and the
        prefer_indications setting. Returns a Waitable that executes when the subscription on the peripheral finishes.

        The Waitable returns two parameters: (GattcCharacteristic this, SubscriptionWriteCompleteEventArgs event args)

        :param on_notification_handler: The handler to be called when an indication or notification is received from
        the peripheral. Must take three parameters: (GattcCharacteristic this, gatt.GattNotificationType, bytearray data)
        :param prefer_indications: If the peripheral supports both indications and notifications,
                                   will subscribe to indications instead of notifications
        :return: A Waitable that will fire when the subscription finishes
        :rtype: blatann.waitables.EventWaitable
        :raises: InvalidOperationException if the characteristic cannot be subscribed to
                (characteristic does not support indications or notifications)
        """
        if not self.subscribable:
            raise InvalidOperationException(
                "Cannot subscribe to Characteristic {}".format(self.uuid))
        if prefer_indications and self._properties.indicate or not self._properties.notify:
            value = gatt.SubscriptionState.INDICATION
        else:
            value = gatt.SubscriptionState.NOTIFY
        self._on_notification_event.register(on_notification_handler)

        write_id = self._manager.write(self.cccd_handle,
                                       gatt.SubscriptionState.to_buffer(value))
        return IdBasedEventWaitable(self._on_cccd_write_complete_event,
                                    write_id)
Exemple #3
0
    def notify(
        self, data
    ) -> EventWaitable[GattsCharacteristic, NotificationCompleteEventArgs]:
        """
        Notifies the client with the data provided without setting the data into the characteristic value.
        If data is not provided (None), will notify with the currently-set value of the characteristic

        :param data: The data to notify the client with
        :return: An EventWaitable that will fire when the notification is successfully sent to the client. The waitable
                 also contains the ID of the sent notification which is used in the on_notify_complete event
        :rtype: NotificationCompleteEventWaitable
        """
        if isinstance(data, BleDataStream):
            value = data.value
        if isinstance(data, str):
            value = data.encode(self.string_encoding)
        if not self.notifiable:
            raise InvalidOperationException(
                "Cannot notify client. "
                "{} not set up for notifications or indications".format(
                    self.uuid))
        if not self.client_subscribed:
            raise InvalidStateException(
                "Client is not subscribed, cannot notify client")

        notification_id = self._notification_manager.notify(
            self, self.value_handle, self._on_notify_complete, data)
        return IdBasedEventWaitable(self._on_notify_complete, notification_id)
Exemple #4
0
    def subscribe(
        self,
        on_notification_handler: Callable[
            [GattcCharacteristic, NotificationReceivedEventArgs], None],
        prefer_indications=False
    ) -> EventWaitable[GattcCharacteristic,
                       SubscriptionWriteCompleteEventArgs]:
        """
        Subscribes to the characteristic's indications or notifications, depending on what's available and the
        prefer_indications setting. Returns a Waitable that triggers when the subscription on the peripheral finishes.

        :param on_notification_handler: The handler to be called when an indication or notification is received from
            the peripheral. Must take two parameters: (GattcCharacteristic this, NotificationReceivedEventArgs event args)
        :param prefer_indications: If the peripheral supports both indications and notifications,
            will subscribe to indications instead of notifications
        :return: A Waitable that will trigger when the subscription finishes
        :raises: InvalidOperationException if the characteristic cannot be subscribed to
            (characteristic does not support indications or notifications)
        """
        if not self.subscribable:
            raise InvalidOperationException(
                "Cannot subscribe to Characteristic {}".format(self.uuid))
        if prefer_indications and self._properties.indicate or not self._properties.notify:
            value = gatt.SubscriptionState.INDICATION
        else:
            value = gatt.SubscriptionState.NOTIFY
        self._on_notification_event.register(on_notification_handler)
        waitable = self._cccd_attr.write(
            gatt.SubscriptionState.to_buffer(value))
        return IdBasedEventWaitable(self._on_cccd_write_complete_event,
                                    waitable.id)
Exemple #5
0
    def read(self) -> IdBasedEventWaitable[GattcAttribute, ReadCompleteEventArgs]:
        """
        Performs a read of the attribute and returns a Waitable that executes when the read finishes
        with the data read.

        :return: A waitable that will trigger when the read finishes
        """
        read_id = self._manager.read(self._handle, self._read_complete)
        return IdBasedEventWaitable(self._on_read_complete_event, read_id)
Exemple #6
0
    def read(self) -> EventWaitable[GattcCharacteristic, ReadCompleteEventArgs]:
        """
        Initiates a read of the characteristic and returns a Waitable that executes when the read finishes with
        the data read.

        The Waitable returns two parameters: (GattcCharacteristic this, ReadCompleteEventArgs event args)

        :return: A waitable that will fire when the read finishes
        :raises: InvalidOperationException if characteristic not readable
        """
        if not self.readable:
            raise InvalidOperationException("Characteristic {} is not readable".format(self.uuid))
        read_id = self._manager.read(self.value_handle)
        return IdBasedEventWaitable(self._on_read_complete_event, read_id)
Exemple #7
0
    def read(
            self) -> EventWaitable[GattcCharacteristic, ReadCompleteEventArgs]:
        """
        Initiates a read of the characteristic and returns a Waitable that triggers when the read finishes with
        the data read.

        :return: A waitable that will trigger when the read finishes
        :raises: InvalidOperationException if characteristic not readable
        """
        if not self.readable:
            raise InvalidOperationException(
                "Characteristic {} is not readable".format(self.uuid))
        waitable = self._value_attr.read()
        return IdBasedEventWaitable(self._on_read_complete_event, waitable.id)
Exemple #8
0
    def write(self, data, with_response=True) -> IdBasedEventWaitable[GattcAttribute, WriteCompleteEventArgs]:
        """
        Initiates a write of the data provided to the attribute and returns a Waitable that executes
        when the write completes and the confirmation response is received from the other device.

        :param data: The data to write. Can be a string, bytes, or anything that can be converted to bytes
        :type data: str or bytes or bytearray
        :param with_response: Used internally for characteristics that support write without responses.
                              Should always be true for any other case (descriptors, etc.).
        :return: A waitable that returns when the write finishes
        """
        if isinstance(data, str):
            data = data.encode(self._string_encoding)
        write_id = self._manager.write(self._handle, bytes(data), self._write_complete, with_response)
        return IdBasedEventWaitable(self._on_write_complete_event, write_id)
Exemple #9
0
    def write(self, data):
        """
        Initiates a write of the data provided to the characteristic and returns a Waitable that executes
        when the write completes.

        The Waitable returns two parameters: (GattcCharacteristic this, WriteCompleteEventArgs event args)

        :param data: The data to write. Can be a string, bytearray, or anything that can be converted to a bytearray
        :return: A waitable that returns when the write finishes
        :rtype: blatann.waitables.EventWaitable
        :raises: InvalidOperationException if characteristic is not writable
        """
        if not self.writable:
            raise InvalidOperationException(
                "Characteristic {} is not writable".format(self.uuid))
        write_id = self._manager.write(self.value_handle, bytearray(data))
        return IdBasedEventWaitable(self._on_write_complete_event, write_id)
Exemple #10
0
    def unsubscribe(self) -> EventWaitable[GattcCharacteristic, SubscriptionWriteCompleteEventArgs]:
        """
        Unsubscribes from indications and notifications from the characteristic and clears out all handlers
        for the characteristic's on_notification event handler. Returns a Waitable that executes when the unsubscription
        finishes.

        The Waitable returns two parameters: (GattcCharacteristic this, SubscriptionWriteCompleteEventArgs event args)

        :return: A Waitable that will fire when the unsubscription finishes
        """
        if not self.subscribable:
            raise InvalidOperationException("Cannot subscribe to Characteristic {}".format(self.uuid))
        value = gatt.SubscriptionState.NOT_SUBSCRIBED
        write_id = self._manager.write(self.cccd_handle, gatt.SubscriptionState.to_buffer(value))
        self._on_notification_event.clear_handlers()

        return IdBasedEventWaitable(self._on_cccd_write_complete_event, write_id)
Exemple #11
0
    def write(
            self, data
    ) -> EventWaitable[GattcCharacteristic, WriteCompleteEventArgs]:
        """
        Performs a write request of the data provided to the characteristic and returns a Waitable that triggers
        when the write completes and the confirmation response is received from the other device.

        :param data: The data to write. Can be a string, bytes, or anything that can be converted to bytes
        :type data: str or bytes or bytearray
        :return: A waitable that returns when the write finishes
        :raises: InvalidOperationException if characteristic is not writable
        """
        if not self.writable:
            raise InvalidOperationException(
                "Characteristic {} is not writable".format(self.uuid))
        if isinstance(data, str):
            data = data.encode(self.string_encoding)
        waitable = self._value_attr.write(bytes(data), True)
        return IdBasedEventWaitable(self._on_write_complete_event, waitable.id)
Exemple #12
0
    def write_without_response(
            self, data
    ) -> EventWaitable[GattcCharacteristic, WriteCompleteEventArgs]:
        """
        Performs a write command, which does not require the peripheral to send a confirmation response packet.
        This is a faster but lossy operation in the case that the packet is dropped/never received by the peer.
        This returns a waitable that triggers when the write is transmitted to the peripheral device.

        .. note:: Data sent without responses must fit within a single MTU minus 3 bytes for the operation overhead.

        :param data: The data to write. Can be a string, bytes, or anything that can be converted to bytes
        :type data: str or bytes or bytearray
        :return: A waitable that returns when the write finishes
        :raises: InvalidOperationException if characteristic is not writable without responses
        """
        if not self.writable_without_response:
            raise InvalidOperationException(
                "Characteristic {} does not accept "
                "writes without responses".format(self.uuid))
        if isinstance(data, str):
            data = data.encode(self.string_encoding)
        waitable = self._value_attr.write(bytes(data), False)
        return IdBasedEventWaitable(self._on_write_complete_event, waitable.id)
Exemple #13
0
    def unsubscribe(
        self
    ) -> EventWaitable[GattcCharacteristic,
                       SubscriptionWriteCompleteEventArgs]:
        """
        Unsubscribes from indications and notifications from the characteristic and clears out all handlers
        for the characteristic's on_notification event handler. Returns a Waitable that triggers when the unsubscription
        finishes.

        :return: A Waitable that will trigger when the unsubscription operation finishes
        :raises: InvalidOperationException if characteristic cannot be subscribed to
            (characteristic does not support indications or notifications)
        """
        if not self.subscribable:
            raise InvalidOperationException(
                "Cannot subscribe to Characteristic {}".format(self.uuid))
        value = gatt.SubscriptionState.NOT_SUBSCRIBED
        waitable = self._cccd_attr.write(
            gatt.SubscriptionState.to_buffer(value))
        self._on_notification_event.clear_handlers()

        return IdBasedEventWaitable(self._on_cccd_write_complete_event,
                                    waitable.id)
Exemple #14
0
 def read_time(self) -> EventWaitable[CurrentTimeClient, DecodedReadCompleteEventArgs[CurrentTime]]:
     """
     Reads the time from the server
     """
     event = self._current_time_char.read().then(self._current_time_dispatcher)
     return IdBasedEventWaitable(self._on_current_time_updated_event, event.id)
Exemple #15
0
 def read_time(self):
     event = self._current_time_char.read().then(self._current_time_dispatcher)
     return IdBasedEventWaitable(self._on_current_time_updated_event, event.id)