def main(serial_port): # Create and open te device ble_device = BleDevice(serial_port) ble_device.open() # Create and add the Device Info Service to the database dis = device_info.add_device_info_service(ble_device.database) # Set some characteristics in the DIS. The service only contains characteristics which # have values set. The other ones are not present dis.set_software_revision("14.2.1") dis.set_hardware_revision("A") dis.set_firmware_revision("1.0.4") dis.set_serial_number("AB1234") pnp_id = device_info.PnpId(device_info.PnpVendorSource.bluetooth_sig, 0x0058, 0x0002, 0x0013) dis.set_pnp_id(pnp_id) # Initiate the advertising data. Advertise the name and DIS service UUID name = "Peripheral DIS" adv_data = advertising.AdvertisingData(local_name=name, service_uuid16s=device_info.DIS_SERVICE_UUID) ble_device.advertiser.set_advertise_data(adv_data) # Start advertising logger.info("Advertising") ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) ble_device.advertiser.start(timeout_sec=0, auto_restart=True) # Create a waitable that will never fire, and wait for some time w = GenericWaitable() w.wait(60*30, exception_on_timeout=False) # Keep device active for 30 mins # Cleanup logger.info("Done") ble_device.close()
def main(serial_port): stop_event = threading.Event() threading.Thread(target=wait_for_user_stop, args=(stop_event, )).start() time.sleep(2) ble_device = BleDevice(serial_port) ble_device.open() interval_ms = 100 # Send out an advertising packet every 500ms timeout_sec = 0 # Advertise forever mode = AdvertisingMode.non_connectable_undirected # Set mode to not allow connections adv_flags = AdvertisingFlags.BR_EDR_NOT_SUPPORTED | AdvertisingFlags.GENERAL_DISCOVERY_MODE adv_data = AdvertisingData(flags=adv_flags, local_name="Time", service_data=_get_time_service_data()) ble_device.advertiser.set_advertise_data(adv_data) ble_device.advertiser.start(interval_ms, timeout_sec, auto_restart=True, advertise_mode=mode) while True: # Update the advertising data every 1 second stop_event.wait(1) if stop_event.is_set( ): # User stopped execution, break out and stop advertising break # Update the service data and set it in the BLE device adv_data.service_data = _get_time_service_data() ble_device.advertiser.set_advertise_data(adv_data) ble_device.advertiser.stop() ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.open() # Create and add the current time service to the database. # Tweak the flags below to change how the service is set up current_time_service = current_time.add_current_time_service(ble_device.database, enable_writes=True, enable_local_time_info=True, enable_reference_info=False) # Register handlers for when the characteristics are written to. # These will only be triggered if enable_writes above is true current_time_service.on_current_time_write.register(on_current_time_write) current_time_service.on_local_time_info_write.register(on_local_time_info_write) # Demo of the different ways to manually or automatically control the reported time # Example 1: Automatically reference system time. # All logic is handled within the service and reports the time whenever the characteristic is read # Example 2: Manually report the time 1 day behind using callback method. # Register a user-defined callback to retrieve the current time to report back to the client # Example 3: Manually report the time 1 hour ahead by setting the base time # Set the characteristic's base time to 1 day ahead and allow the service to auto-increment from there example_mode = 1 if example_mode == 1: # configure_automatic() also sets up the Local Time characteristic (if enabled) # to just set the automatic time and leave Local Time unconfigured, use set_time() with no parameters current_time_service.configure_automatic() elif example_mode == 2: def on_time_read(): d = datetime.datetime.now() - datetime.timedelta(days=1) logger.info("Getting time: {}".format(d)) return d current_time_service.set_time(characteristic_read_callback=on_time_read) elif example_mode == 3: base_time = datetime.datetime.now() + datetime.timedelta(hours=1) current_time_service.set_time(base_time) # Register listeners for when the client connects and disconnects ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) # Advertise the Current Time service adv_data = advertising.AdvertisingData(local_name="Current Time", flags=0x06, service_uuid16s=current_time.CURRENT_TIME_SERVICE_UUID) ble_device.advertiser.set_advertise_data(adv_data) logger.info("Advertising") ble_device.advertiser.start(timeout_sec=0, auto_restart=True) # Create a waitable that waits 5 minutes, then exits w = GenericWaitable() w.wait(5 * 60, exception_on_timeout=False) logger.info("Done") ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.configure() ble_device.open() # Set up desired security parameters ble_device.client.security.set_security_params(passcode_pairing=False, bond=False, lesc_pairing=False, io_capabilities=IoCapabilities.DISPLAY_ONLY, out_of_band=False) ble_device.client.security.on_pairing_complete.register(on_client_pairing_complete) ble_device.client.security.on_passkey_display_required.register(on_passkey_display) ble_device.client.security.on_passkey_required.register(on_passkey_entry) ble_device.client.security.on_security_level_changed.register(on_security_level_changed) # Create and add the math service service = ble_device.database.add_service(constants.MATH_SERVICE_UUID) # Create and add the hex conversion characteristic to the service hex_conv_char = service.add_characteristic(constants.HEX_CONVERT_CHAR_UUID, constants.HEX_CONVERT_CHAR_PROPERTIES, "Test Data") # Register the callback for when a write occurs and subscription state changes hex_conv_char.on_write.register(on_hex_conversion_characteristic_write) hex_conv_char.on_subscription_change.register(on_gatts_subscription_state_changed) # Create and add the counting characteristic, initializing the data to [0, 0, 0, 0] counting_char = service.add_characteristic(constants.COUNTING_CHAR_UUID, constants.COUNTING_CHAR_PROPERTIES, [0]*4) counting_char.on_subscription_change.register(on_gatts_subscription_state_changed) # Create the thread for the counting characteristic counting_char_thread = CountingCharacteristicThread(counting_char) # Create and add the time service time_service = ble_device.database.add_service(constants.TIME_SERVICE_UUID) # Add the time characteristic and register the callback for when its read time_char = time_service.add_characteristic(constants.TIME_CHAR_UUID, constants.TIME_CHAR_PROPERTIES, "Time") time_char.on_read.register(on_time_char_read) # Initialize the advertising and scan response data adv_data = advertising.AdvertisingData(local_name=constants.PERIPHERAL_NAME, flags=0x06) scan_data = advertising.AdvertisingData(service_uuid128s=constants.TIME_SERVICE_UUID, has_more_uuid128_services=True) ble_device.advertiser.set_advertise_data(adv_data, scan_data) # Start advertising logger.info("Advertising") ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) ble_device.advertiser.start(timeout_sec=0, auto_restart=True) # Create a waitable that will never fire, and wait for some time w = GenericWaitable() w.wait(60*30, exception_on_timeout=False) # Keep device active for 30 mins # Cleanup counting_char_thread.join() logger.info("Done") ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.open() # Create a database to store the readings glucose_database = glucose.BasicGlucoseDatabase() # Add the service to the BLE database, using the glucose database just created, require encryption at the minimum service = glucose.add_glucose_service(ble_device.database, glucose_database, glucose.SecurityLevel.JUST_WORKS) # Set the features of this "glucose sensor" features = glucose.GlucoseFeatures( GlucoseFeatureType.low_battery_detection, GlucoseFeatureType.strip_insertion_error_detection) service.set_features(features) # Add some measurements to the glucose database add_fake_glucose_readings(glucose_database) # Register listeners for when the client connects and disconnects ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) # Set the connection parameters for the client ble_device.client.set_connection_parameters(15, 30, 4000) # Set the function to display the passkey ble_device.client.security.on_passkey_display_required.register( display_passkey) # Set the security parameters for the client ble_device.client.security.set_security_params( passcode_pairing=False, bond=False, io_capabilities=IoCapabilities.DISPLAY_ONLY, out_of_band=False) # Advertise the Glucose service adv_data = advertising.AdvertisingData( local_name="Glucose Test", flags=0x06, service_uuid16s=glucose.GLUCOSE_SERVICE_UUID) ble_device.advertiser.set_advertise_data(adv_data) logger.info("Advertising") ble_device.advertiser.start(timeout_sec=0, auto_restart=True) # Create a waitable that will never fire, and wait for some time w = GenericWaitable() w.wait(60 * 30, exception_on_timeout=False) # Keep device active for 30 mins logger.info("Done") ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.open() logger.info("Scanning...") # Set scanning for 4 seconds ble_device.scanner.set_default_scan_params(timeout_seconds=4) # Start scanning and wait for it to complete scan_report = ble_device.scanner.start_scan().wait() print("") logger.info("Finished scanning. Scan reports:") # Iterate through all the peers found and print out the reports for report in scan_report.advertising_peers_found: logger.info(report) # Clean up and close the device ble_device.close()
def main(serial_port): ble_device = BleDevice(serial_port) # 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() # Create and add the Nordic UART service nus = nordic_uart.add_nordic_uart_service(ble_device.database) nus.on_data_received.register(on_data_rx) nus.on_write_complete.register(on_tx_complete) # Register listeners for when the client connects and disconnects ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) ble_device.client.on_mtu_size_updated.register(on_mtu_size_update) # Configure the client to prefer the max MTU size ble_device.client.preferred_mtu_size = ble_device.max_mtu_size ble_device.client.set_connection_parameters(7.5, 15, 4000) # Advertise the service UUID adv_data = advertising.AdvertisingData(flags=0x06, local_name="Nordic UART Server") scan_data = advertising.AdvertisingData( service_uuid128s=nordic_uart.NORDIC_UART_SERVICE_UUID) ble_device.advertiser.set_advertise_data(adv_data, scan_data) logger.info("Advertising") ble_device.advertiser.start(timeout_sec=0, auto_restart=True) # Create a waitable that waits 5 minutes then exits w = GenericWaitable() try: w.wait(5 * 60, exception_on_timeout=False) except KeyboardInterrupt: pass finally: ble_device.close()
def main(serial_port): target_device_name = constants.PERIPHERAL_NAME # Create a waitable that will block the main thread until notified by one of the classes above main_thread_waitable = GenericWaitable() # 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() # Create the connection manager and start the scanning process s = ConnectionManager(ble_device, main_thread_waitable) s.scan_and_connect(target_device_name) # Block the main thread indefinitely until the program finishes main_thread_waitable.wait() # Clean up, disconnect if a peer was connected to if s.peer: s.peer.disconnect().wait() ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.open() # Create and add the battery service to the database battery_service = battery.add_battery_service(ble_device.database, enable_notifications=True) battery_service.set_battery_level(100, False) # Register listeners for when the client connects and disconnects ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) # Leaving security and connection parameters as defaults (don't care) # Advertise the Battery Service adv_data = advertising.AdvertisingData( local_name="Battery Test", flags=0x06, service_uuid16s=battery.BATTERY_SERVICE_UUID) ble_device.advertiser.set_advertise_data(adv_data) logger.info("Advertising") ble_device.advertiser.start(timeout_sec=0, auto_restart=True) battery_level = 100 battery_level_decrement_steps = 1 time_between_steps = 10 # Decrement the battery level until it runs out while battery_level >= 0: time.sleep(time_between_steps) battery_level -= battery_level_decrement_steps logger.info("Updating battery level to {}".format(battery_level)) battery_service.set_battery_level(battery_level) logger.info("Done") ble_device.close()
def main(serial_port): # Create and open the device ble_device = BleDevice(serial_port) ble_device.open() logger.info("Scanning...") # Set scanning for 4 seconds ble_device.scanner.set_default_scan_params(timeout_seconds=4) # Start scanning and iterate through the reports as they're received for report in ble_device.scanner.start_scan().scan_reports: if not report.duplicate: logger.info(report) scan_report = ble_device.scanner.scan_report print("\n") logger.info("Finished scanning. Scan reports by peer address:") # Iterate through all the peers found and print out the reports for report in scan_report.advertising_peers_found: logger.info(report) # Clean up and close the device 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) # 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 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): # 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): # Create and open the device ble_device = BleDevice(serial_port) ble_device.configure() ble_device.open() # Create the service service = ble_device.database.add_service( constants.DESC_EXAMPLE_SERVICE_UUID) # Create a characteristic and add some descriptors # NOTE: Some descriptors MUST be added during creation: SCCD, User Description, and Presentation Format # CCCD is added automatically based on the characteristic's Notify and Indicate properties # Define the User Description properties and make it writable # The simplest use-case in which the user description is read-only can provide just the first parameter user_desc_props = gatts.GattsUserDescriptionProperties( "UTC Time", write=True, security_level=smp.SecurityLevel.OPEN, max_length=20, variable_length=True) # Define the presentation format. Returning the time in seconds so set exponent to 0 presentation_format = PresentationFormat(fmt=Format.uint32, exponent=0, unit=Units.time_second) # Create the characteristic properties, including the SCCD, User Description, and Presentation Format char_props = gatts.GattsCharacteristicProperties( read=True, write=False, notify=True, max_length=Uint32.byte_count, variable_length=False, sccd=True, user_description=user_desc_props, presentation_format=presentation_format) char = service.add_characteristic(constants.DESC_EXAMPLE_CHAR_UUID, char_props, Uint32.encode(0)) char.on_read.register(on_read) # Add another descriptor to the list char_range_value = Uint32.encode(5555) + Uint32.encode(2**32 - 1000) desc_props = GattsAttributeProperties(read=True, write=False, variable_length=False, max_length=len(char_range_value)) char.add_descriptor(DescriptorUuid.valid_range, desc_props, char_range_value) # Initialize the advertising and scan response data adv_data = advertising.AdvertisingData( local_name=constants.PERIPHERAL_NAME, flags=0x06) scan_data = advertising.AdvertisingData( service_uuid128s=constants.DESC_EXAMPLE_SERVICE_UUID, has_more_uuid128_services=False) ble_device.advertiser.set_advertise_data(adv_data, scan_data) # Start advertising logger.info("Advertising") ble_device.client.on_connect.register(on_connect) ble_device.client.on_disconnect.register(on_disconnect) ble_device.advertiser.start(timeout_sec=0, auto_restart=True) # Create a waitable that will never fire, and wait for some time w = GenericWaitable() w.wait(60 * 30, exception_on_timeout=False) # Keep device active for 30 mins logger.info("Done") 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()