Exemplo n.º 1
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)
Exemplo n.º 2
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)
Exemplo n.º 3
0
 def type(self):
     if self.char.cccd_state == gatt.SubscriptionState.INDICATION:
         return nrf_types.BLEGattHVXType.indication
     elif self.char.cccd_state == gatt.SubscriptionState.NOTIFY:
         return nrf_types.BLEGattHVXType.notification
     else:
         raise InvalidStateException("Client not subscribed")
Exemplo n.º 4
0
    def pair(self, force_repairing=False):
        """
        Starts the encrypting process with the peer. If the peer has already been bonded to,
        Starts the pairing process with the peer given the set security parameters
        and returns a Waitable which will fire when the pairing process completes, whether successful or not.
        Waitable returns two parameters: (Peer, PairingCompleteEventArgs)

        :return: A waitiable that will fire when pairing is complete
        :rtype: blatann.waitables.EventWaitable
        """
        if self._pairing_in_process or self._initiated_encryption:
            raise InvalidStateException("Security manager busy")
        if self.security_params.reject_pairing_requests:
            raise InvalidOperationException(
                "Cannot initiate pairing while rejecting pairing requests")

        # if in the client role and don't want to force a re-pair, check for bonding data first
        if self.peer.is_peripheral and not force_repairing:
            bond_entry = self._find_db_entry(self.peer.peer_address)
            if bond_entry:
                logger.info("Re-establishing encryption with peer using LTKs")
                self.ble_device.ble_driver.ble_gap_encrypt(
                    self.peer.conn_handle,
                    bond_entry.bonding_data.own_ltk.master_id,
                    bond_entry.bonding_data.own_ltk.enc_info)
                self._initiated_encryption = True

        sec_params = self._get_security_params()
        self.ble_device.ble_driver.ble_gap_authenticate(
            self.peer.conn_handle, sec_params)
        self._pairing_in_process = True
        return EventWaitable(self.on_pairing_complete)
Exemplo n.º 5
0
    def write(self, handle, data):
        """
        Writes data to the attribute at the handle provided. Can only write to a single attribute at a time.
        If a write is in progress, raises an InvalidStateException

        :param handle: The attribute handle to write
        :param data: The data to write
        :return: A Waitable that will fire when the write finishes. see on_write_complete for the values returned from the waitable
        :rtype: EventWaitable
        """
        if self._busy:
            raise InvalidStateException("Gattc Writer is busy")
        if len(data) == 0:
            raise ValueError("Data must be at least one byte")

        self._offset = 0
        self._handle = handle
        self._data = data
        logger.debug("Starting write to handle {}, len: {}".format(self._handle, len(self._data)))
        try:
            self._busy = True
            self._write_next_chunk()
        except Exception:
            self._busy = False
            raise
        return EventWaitable(self.on_write_complete)
Exemplo n.º 6
0
 def notify(self, characteristic, handle, event_on_complete, data=None):
     if characteristic.cccd_state == gatt.SubscriptionState.INDICATION:
         manager = self._indication_manager
     elif characteristic.cccd_state == gatt.SubscriptionState.NOTIFY:
         manager = self._notification_manager
     else:
         raise InvalidStateException("Client not subscribed")
     return manager.notify(characteristic, handle, event_on_complete, data)
Exemplo n.º 7
0
 def __init__(self, connected_peer):
     """
     :type ble_device: blatann.device.BleDevice
     :type connected_peer: blatann.peer.Peer
     """
     super(DisconnectionWaitable, self).__init__(n_args=2)
     if not connected_peer:
         raise InvalidStateException("Peer already disconnected")
     connected_peer.on_disconnect.register(self._on_disconnect)
Exemplo n.º 8
0
    def read(self, handle):
        """
        Reads the attribute value from the handle provided. Can only read from a single attribute at a time. If a
        read is in progress, raises an InvalidStateException

        :param handle: the attribute handle to read
        :return: A waitable that will fire when the read finishes.
                 See on_read_complete for the values returned from the waitable
        :rtype: EventWaitable
        """
        if self._busy:
            raise InvalidStateException("Gattc Reader is busy")
        self._handle = handle
        self._offset = 0
        self._data = bytearray()
        logger.debug("Starting read from handle {}".format(handle))
        self._read_next_chunk()
        self._busy = True
        return EventWaitable(self.on_read_complete)
Exemplo n.º 9
0
    def pair(self):
        """
        Starts the pairing process with the peer given the set security parameters
        and returns a Waitable which will fire when the pairing process completes, whether successful or not.
        Waitable returns two parameters: (Peer, PairingCompleteEventArgs)

        :return: A waitiable that will fire when pairing is complete
        :rtype: blatann.waitables.EventWaitable
        """
        if self._busy:
            raise InvalidStateException("Security manager busy")
        if self.security_params.reject_pairing_requests:
            raise InvalidOperationException(
                "Cannot initiate pairing while rejecting pairing requests")

        sec_params = self._get_security_params()
        self.ble_device.ble_driver.ble_gap_authenticate(
            self.peer.conn_handle, sec_params)
        self._busy = True
        return EventWaitable(self.on_pairing_complete)