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)
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)
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")
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)
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)
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)
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)
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)
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)