def main(serial_port): # Open the BLE Device and suppress spammy log messages ble_device = BleDevice(serial_port) ble_device.event_logger.suppress(nrf_events.GapEvtAdvReport) # Configure the BLE device to support MTU sizes which allow the max data length extension PDU size # Note this isn't 100% necessary as the default configuration sets the max to this value also ble_device.configure(att_mtu_max_size=MTU_SIZE_FOR_MAX_DLE) ble_device.open() # Set scan duration for 4 seconds ble_device.scanner.set_default_scan_params(timeout_seconds=4) ble_device.set_default_peripheral_connection_params(10, 30, 4000) logger.info("Scanning for peripherals advertising UUID {}".format( nordic_uart.NORDIC_UART_SERVICE_UUID)) target_address = None # Start scan and wait for it to complete scan_report = ble_device.scanner.start_scan().wait() # Search each peer's advertising data for the Nordic UART Service UUID to be advertised for report in scan_report.advertising_peers_found: if nordic_uart.NORDIC_UART_SERVICE_UUID in report.advertise_data.service_uuid128s and report.device_name == "Nordic UART Server": target_address = report.peer_address break if not target_address: logger.info("Did not find peripheral advertising Nordic UART service") return # Initiate connection and wait for it to finish logger.info("Found match: connecting to address {}".format(target_address)) peer = ble_device.connect(target_address).wait() if not peer: logger.warning("Timed out connecting to device") return logger.info("Connected, conn_handle: {}".format(peer.conn_handle)) logger.info("Exchanging MTU") peer.exchange_mtu(peer.max_mtu_size).wait(10) logger.info("MTU Exchange complete, discovering services") # Initiate service discovery and wait for it to complete _, event_args = peer.discover_services().wait(exception_on_timeout=False) logger.info("Service discovery complete! status: {}".format( event_args.status)) uart_service = nordic_uart.find_nordic_uart_service(peer.database) if not uart_service: logger.info( "Failed to find Nordic UART service in peripheral database") peer.disconnect().wait() ble_device.close() return # Initialize the service uart_service.initialize().wait(5) uart_service.on_data_received.register(on_data_rx) while True: data = input("Enter data to send to peripheral (q to exit): ") if data == "q": break uart_service.write(data).wait(10) peer.disconnect().wait() ble_device.close()
def main(serial_port): # Set the target to the peripheral's advertised name target_device_name = constants.PERIPHERAL_NAME # Create and open the BLE device (and suppress spammy logs) ble_device = BleDevice(serial_port) ble_device.event_logger.suppress(nrf_events.GapEvtAdvReport) ble_device.open() # Set the scanner to scan for 4 seconds ble_device.scanner.set_default_scan_params(timeout_seconds=4) logger.info("Scanning for '{}'".format(target_device_name)) target_address = example_utils.find_target_device(ble_device, target_device_name) if not target_address: logger.info("Did not find target peripheral") return # Initiate the connection and wait for it to finish logger.info("Found match: connecting to address {}".format(target_address)) peer = ble_device.connect(target_address).wait() if not peer: logger.warning("Timed out connecting to device") return # Wait up to 10 seconds for service discovery to complete logger.info("Connected, conn_handle: {}".format(peer.conn_handle)) _, event_args = peer.discover_services().wait(10, exception_on_timeout=False) logger.info("Service discovery complete! status: {}".format(event_args.status)) # Log each service found for service in peer.database.services: logger.info(service) peer.set_connection_parameters(100, 120, 6000) # Discovery complete, go to a longer connection interval # Pair with the peripheral def on_passkey_entry(peer, passkey_event_args): """ Callback for when the user is requested to enter a passkey to resume the pairing process. Requests the user to enter the passkey and resolves the event with the passkey entered :param peer: the peer the passkey is for :param passkey_event_args: :type passkey_event_args: blatann.event_args.PasskeyEntryEventArgs """ passkey = input("Enter peripheral passkey: ") passkey_event_args.resolve(passkey) # Setup the security parameters peer.security.set_security_params(passcode_pairing=True, io_capabilities=smp.IoCapabilities.KEYBOARD_DISPLAY, bond=False, out_of_band=False) # Register the callback for when a passkey needs to be entered by the user peer.security.on_passkey_required.register(on_passkey_entry) # Wait up to 60 seconds for the pairing process peer.security.pair().wait(60) # Find the counting characteristic counting_char = peer.database.find_characteristic(constants.COUNTING_CHAR_UUID) if counting_char: logger.info("Subscribing to the counting characteristic") counting_char.subscribe(on_counting_char_notification).wait(5) else: logger.warning("Failed to find counting characteristic") # Find the hex conversion characteristic. This characteristic takes in a bytestream and converts it to its # hex representation. e.g. '0123' -> '30313233' hex_convert_char = peer.database.find_characteristic(constants.HEX_CONVERT_CHAR_UUID) if hex_convert_char: # Generate some data ABCDEFG... Then, incrementally send increasing lengths of strings. # i.e. first send 'A', then 'AB', then 'ABC'... data_to_convert = bytes(ord('A') + i for i in range(12)) for i in range(len(data_to_convert)): data_to_send = data_to_convert[:i+1] logger.info("Converting to hex data: '{}'".format(data_to_send)) # Write the data, waiting up to 5 seconds for the write to complete if not hex_convert_char.write(data_to_send).wait(5, False): logger.error("Failed to write data, i={}".format(i)) break # Write was successful, when we read the characteristic the peripheral should have converted the string # Once again, initiate a read and wait up to 5 seconds for the read to complete char, event_args = hex_convert_char.read().wait(5, False) logger.info("Hex: '{}'".format(event_args.value.decode("ascii"))) else: logger.warning("Failed to find hex convert char") # Clean up logger.info("Disconnecting from peripheral") peer.disconnect().wait() ble_device.close()
def main(serial_port): # Open the BLE Device and suppress spammy log messages ble_device = BleDevice(serial_port) ble_device.event_logger.suppress(nrf_events.GapEvtAdvReport) ble_device.open() # Set scan duration for 4 seconds ble_device.scanner.set_default_scan_params(timeout_seconds=4) logger.info("Scanning for peripherals advertising UUID {}".format( battery.BATTERY_SERVICE_UUID)) target_address = None # Start scan and wait for it to complete scan_report = ble_device.scanner.start_scan().wait() # Search each peer's advertising data for the Battery Service UUID to be advertised for report in scan_report.advertising_peers_found: if battery.BATTERY_SERVICE_UUID in report.advertise_data.service_uuid16s: target_address = report.peer_address break if not target_address: logger.info("Did not find peripheral advertising battery service") return # Initiate connection and wait for it to finish logger.info("Found match: connecting to address {}".format(target_address)) peer = ble_device.connect(target_address).wait() if not peer: logger.warning("Timed out connecting to device") return logger.info("Connected, conn_handle: {}".format(peer.conn_handle)) # Initiate service discovery and wait for it to complete _, event_args = peer.discover_services().wait(10, exception_on_timeout=False) logger.info("Service discovery complete! status: {}".format( event_args.status)) # Find the battery service within the peer's database battery_service = battery.find_battery_service(peer.database) if not battery_service: logger.info("Failed to find Battery Service in peripheral database") peer.disconnect().wait() return # Read out the battery level logger.info("Reading battery level...") _, event_args = battery_service.read().wait() battery_percent = event_args.value logger.info("Battery: {}%".format(battery_percent)) if battery_service.can_enable_notifications: battery_service.on_battery_level_updated.register( on_battery_level_update) battery_service.enable_notifications().wait() wait_duration = 30 logger.info("Waiting {} seconds for any battery notifications") time.sleep(wait_duration) # Clean up logger.info("Disconnecting from peripheral") peer.disconnect().wait() ble_device.close()
def main(serial_port): # Open the BLE Device and suppress spammy log messages ble_device = BleDevice(serial_port) ble_device.event_logger.suppress(nrf_events.GapEvtAdvReport) ble_device.open() # Set scan duration to 4 seconds ble_device.scanner.set_default_scan_params(timeout_seconds=4) logger.info("Scanning for peripherals advertising UUID {}".format( device_info.DIS_SERVICE_UUID)) target_address = None # Start scan and wait for it to complete scan_report = ble_device.scanner.start_scan().wait() # Search each peer's advertising data for the DIS Service UUID to be advertised for report in scan_report.advertising_peers_found: if device_info.DIS_SERVICE_UUID in report.advertise_data.service_uuid16s: target_address = report.peer_address break if not target_address: logger.info("Did not find peripheral advertising DIS service") return # Initiate connection and wait for it to finish logger.info("Found match: connecting to address {}".format(target_address)) peer = ble_device.connect(target_address).wait() if not peer: logger.warning("Timed out connecting to device") return logger.info("Connected, conn_handle: {}".format(peer.conn_handle)) # Initiate service discovery and wait for it to complete _, event_args = peer.discover_services().wait(10, exception_on_timeout=False) logger.info("Service discovery complete! status: {}".format( event_args.status)) # Find the device info service in the peer's database dis = device_info.find_device_info_service(peer.database) if not dis: logger.info( "Failed to find Device Info Service in peripheral database") peer.disconnect().wait() return # Example 1: # Iterate through all possible device info characteristics, read the value if present in service for char in device_info.CHARACTERISTICS: if dis.has(char): logger.info("Reading characteristic: {}...".format(char)) char, event_args = dis.get(char).wait() if isinstance(event_args.value, bytes): value = event_args.value.decode("utf8") else: value = event_args.value logger.info("Value: {}".format(value)) # Example 2: # Read specific characteristics, if present in the service if dis.has_software_revision: char, event_args = dis.get_software_revision().wait() sw_version = event_args.value logger.info("Software Version: {}".format(sw_version.decode("utf8"))) if dis.has_pnp_id: char, event_args = dis.get_pnp_id().wait() pnp_id = event_args.value # type: device_info.PnpId logger.info("Vendor ID: {}".format(pnp_id.vendor_id)) if dis.has_system_id: char, event_args = dis.get_system_id().wait() system_id = event_args.value # type: device_info.SystemId logger.info("System ID: {}".format(system_id)) # Disconnect and close device peer.disconnect().wait() ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.configure() ble_device.open() ble_device.scanner.set_default_scan_params(timeout_seconds=4) # Set the target to the peripheral's advertised name target_device_name = constants.PERIPHERAL_NAME logger.info("Scanning for '{}'".format(target_device_name)) target_address = example_utils.find_target_device(ble_device, target_device_name) if not target_address: logger.info("Did not find target peripheral") return # Initiate the connection and wait for it to finish logger.info("Found match: connecting to address {}".format(target_address)) peer = ble_device.connect(target_address).wait() if not peer: logger.warning("Timed out connecting to device") return logger.info("Connected, conn_handle: {}".format(peer.conn_handle)) # Wait up to 10 seconds for service discovery to complete _, event_args = peer.discover_services().wait(10, exception_on_timeout=False) logger.info("Service discovery complete! status: {}".format(event_args.status)) # Find the Time characteristic time_char = peer.database.find_characteristic(constants.DESC_EXAMPLE_CHAR_UUID) if not time_char: logger.info("Did not find the time characteristic") else: logger.info("Reading all characteristic attributes") for attr in time_char.attributes: logger.info(f"Reading UUID {attr.uuid} - {attr.uuid.description or '[unknown]'}") _, event_args = attr.read().wait(5) if event_args.status == GattStatusCode.success: # Show as hex unless it's the user descriptor UUID which should be a string if attr.uuid == DescriptorUuid.user_description: value = event_args.value.decode("utf8") else: value = binascii.hexlify(event_args.value) logger.info(f" Value: {value}") else: logger.warning(f" Failed to read attribute, status: {event_args.status}") # Read the characteristic's Presentation Format descriptor directly and decode the value presentation_fmt_desc = time_char.find_descriptor(DescriptorUuid.presentation_format) if presentation_fmt_desc: # Read, then decode the value using the PresentationFormat type logger.info("Reading the presentation format descriptor directly") _, event_args = presentation_fmt_desc.read().wait(5) if event_args.status == GattStatusCode.success: try: fmt = PresentationFormat.decode(event_args.value) logger.info(f"Presentation Format: {str(fmt.format)}, Exponent: {fmt.exponent}, Unit: {str(fmt.unit)}") except Exception as e: logger.error("Failed to decode the presentation format descriptor") logger.exception(e) else: logger.info("Failed to find the presentation format descriptor") # Clean up logger.info("Disconnecting from peripheral") peer.disconnect().wait() ble_device.close()