def ble_service_read(address, adapter, addressType, handles, UUIDS, timeout): """ Used by command line tool to read data from device by handle :param address: Address of target BTLE device :param adapter: Host adapter (Empty string to use host's default adapter) :param addressType: Type of address you want to connect to [public | random] :param securityLevel: Security level [low | medium | high] :param handles: List of handles to read from :param UUIDS: List of UUIDs to read from :param maxTries: Maximum number of times to attempt each write operation. Default: 5 :type address: str :type adapter: str :type addressType: str :type securityLevel: str :type handles: list of base 10 ints :type UUIDS: list of strings :type maxTries: int :return: uuidData, handleData :rtype: list of (UUID, data) tuples and list of (handle, data) tuples """ with connection_manager.BLEConnectionManager( adapter, 'central') as connectionManager: connection = connectionManager.init_connection(address, addressType) success = connectionManager.connect(connection) if not success: print("Failed to connected to target device") return uuidData = [] handleData = [] for handle in handles: if handle is not None: tries = 0 if not connectionManager.is_connected(connection): connectionManager.connect(connection) req = connectionManager.gatt_read_handle(connection, int(handle, 16), timeout=timeout) if req.has_error(): handleData.append((handle, req.get_error_message())) else: handleData.append((handle, req.response.data)) for UUID in UUIDS: if UUID is not None: tries = 0 if not connectionManager.is_connected(connection): connectionManager.connect(connection) req = connectionManager.gatt_read_uuid(connection, UUID, timeout=timeout) if req.has_error(): uuidData.append((UUID, req.get_error_message())) else: uuidData.append((UUID, req.response.data)) # returns list of tuples (handle, data) return uuidData, handleData
def ble_service_scan(address, adapter, addressType): """ Used by command line tool to initiate and print results for a scan of all services, characteristics, and descriptors present on a BTLE device. :param address: Address of target BTLE device :param adapter: Host adapter (Empty string to use host's default adapter) :param addressType: Type of address you want to connect to [public | random] :param securityLevel: Security level [low | medium | high] :type address: str :type adapter: str :type addressType: str :type securityLevel: str :return: """ if address is None: raise Exception( "%s Bluetooth address is not valid. Please supply a valid Bluetooth address value." % address) with connection_manager.BLEConnectionManager( adapter, 'central') as connectionManager: connection = connectionManager.init_connection(address, addressType) success = connectionManager.connect(connection) if not success: print("Failed to connected to target device") return device = connectionManager.gatt_discover_primary_services(connection) device = connectionManager.gatt_discover_characteristics(connection, device=device) device = connectionManager.gatt_discover_descriptors(connection, device=device) device.print_device_structure()
def ble_run_smart_scan(address, adapter, addressType, skip_device_info_query=False, attempt_read=True, timeout=None): """ Used by command line tool to initiate and print results for a scan of all services, characteristics, and descriptors present on a BTLE device. :param address: Address of target BTLE device :param adapter: Host adapter (Empty string to use host's default adapter) :param addressType: Type of address you want to connect to [public | random] :param securityLevel: Security level [low | medium | high] :type address: str :type adapter: str :type addressType: str :type securityLevel: str :return:/usr/lib/python2.7/json/decoder.py """ if address is None: raise Exception("%s Bluetooth address is not valid. Please supply a valid Bluetooth address value." % address) with connection_manager.BLEConnectionManager(adapter, 'central') as connectionManager: logger.debug("ConnectionManager available") connection = connectionManager.init_connection(address, addressType) success = connectionManager.connect(connection) if not success: print "Failed to connected to target device" return None logger.debug("Connected!") device = connectionManager.smart_scan(connection, device=None, look_for_device_info=(not skip_device_info_query), attempt_desc_read=attempt_read, timeout=timeout) return device
def general_scan(adapter=0, timeout=50): """ Scan for BTLE Devices and print out results :param timeout: Scan timeout (seconds) :param adapter: Host adapter to use for scanning (Use empty string to use host's default adapter) :type timeout: int :type adapter: str :return: Discovered devices ({<address>:(<addressType>, <data>)}) :rtype: dict """ if timeout < 0: raise Exception( "%s is an invalid scan timeout value. The timeout must be a positive integer" % timeout) with connection_manager.BLEConnectionManager( adapter, "central") as connectionManager: connectionManager.start_scan() start = time.time() * 1000 logger.debug("Starting sleep loop") while ((time.time() * 1000) - start) < (timeout * 1000): logger.debug("Scanning...") gevent.sleep(1) connectionManager.stop_scan() logger.debug("Done scanning!") discovered_devices = connectionManager.get_discovered_devices() return discovered_devices
def ble_service_write(address, adapter, addressType, handles, inputs, timeout): """ Used by command line tool to wrtie data to a device handle :param address: Address of target BTLE device :param adapter: Host adapter (Empty string to use host's default adapter) :param addressType: Type of address you want to connect to [public | random] :param securityLevel: Security level [low | medium | high] :param handles: List of handles to write to :param inputs: List of strings to write to handles :param maxTries: Maximum number of times to attempt each write operation. Default: 5 :type address: str :type adapter: str :type addressType: str :type securityLevel: str :type handles: list of base 10 ints :type inputs: list of strings :type maxTries: int :return: list of (handle, data, input) :rtype: list of tuples (int, str, str) """ with connection_manager.BLEConnectionManager( adapter, 'central') as connectionManager: connection = connectionManager.init_connection(address, addressType) success = connectionManager.connect(connection) if not success: print("Failed to connected to target device") return handleData = [] for inputVal in inputs: for handle in handles: if handle is not None: tries = 0 if not connectionManager.is_connected(connection): connectionManager.connect(connection) req = connectionManager.gatt_write_handle(connection, int(handle, 16), inputVal, timeout=timeout) if req.has_error(): handleData.append( (handle, req.get_error_message(), inputVal)) else: handleData.append( (handle, req.response.data, inputVal)) return handleData
def scan_device(adapter, address, address_type="random", skip_device_info_query=False, attempt_read=False, timeout=None): with connection_manager.BLEConnectionManager( adapter, 'central') as connectionManager: print "Smart scanning for clone" connection = connectionManager.init_connection(address, address_type) success = connectionManager.connect(connection) if not success: print "Failed to connected to target device" return None target_device = connectionManager.smart_scan( connection, device=None, look_for_device_info=(not skip_device_info_query), attempt_desc_read=attempt_read, timeout=timeout) return target_device
def ble_service_read_async(address, adapter, addressType, handles, UUIDS, timeout=5): """ Used by command line tool to read data from device by handle using the async method. As of now, errors are not returned when reading asynchronously, so a timeout must be specified to determine when we should stop looking for a response from a device. (Note: This call is blocking until responses are received or a timeout is reached). :param address: Address of target BTLE device :param adapter: Host adapter (Empty string to use host's default adapter) :param addressType: Type of address you want to connect to [public | random] :param securityLevel: Security level [low | medium | high] :param handles: List of handles to read from :param UUIDS: List of UUIDs to read from :param maxTries: Maximum number of times to attempt each write operation. Default: 5 :param timeout: Time (in seconds) until each read times out if there's an issue. Default: 5 :type address: str :type adapter: str :type addressType: str :type securityLevel: str :type handles: list of base 10 ints :type UUIDS: list of strings :type maxTries: int :type timeout: int :return: uuidData, handleData :rtype: list of (UUID, data) tuples and list of (handle, data) tuples """ import time import gevent with connection_manager.BLEConnectionManager( adapter, 'central') as connectionManager: connection = connectionManager.init_connection(address, addressType) success = connectionManager.connect(connection) if not success: print("Failed to connected to target device") return uuidRequests = [] handleRequests = [] handleRequestQueue = [] uuidRequestQueue = [] for handle in handles: if handle is not None: tries = 0 if not connectionManager.is_connected(connection): connectionManager.connect(connection) logger.debug("Attempting to read from handle: %s" % handle) req = connectionManager.gatt_read_handle_async(connection, int(handle, 16), timeout=timeout) handleRequestQueue.append((handle, req, req.creation_time)) for UUID in UUIDS: if UUID is not None: tries = 0 if not connectionManager.is_connected(connection): connectionManager.connect(connection) logger.debug("Attempting to read from UUID: %s" % UUID) req = connectionManager.gatt_read_uuid_async(connection, UUID, timeout=timeout) uuidRequestQueue.append((UUID, req, req.creation_time)) #returns list of tuples (handle, data) while True: for i in handleRequestQueue: req = i[1] if req.has_response(): data = req.response.data logger.debug("Handle: %s Received data: %s" % (i[0], data)) handleRequests.append((i[0], data)) handleRequestQueue.remove(i) elif req.has_error(): error = req.get_error_message() logger.debug("Handle: %s Error message: %s" % (i[0], error)) handleRequests.append((i[0], error)) handleRequestQueue.remove(i) logger.debug("Response creation time: %s current time: %s" % (i[2], time.time())) for i in uuidRequestQueue: req = i[1] if req.has_response(): data = req.response.data logger.debug("UUID: %s Received data: %s" % (i[0], data)) uuidRequests.append((i[0], data)) uuidRequestQueue.remove(i) elif req.has_error(): error = req.get_error_message() uuidRequests.append((i[0], error)) uuidRequestQueue.remove(i) logger.debug("Response creation time: %s current time: %s" % (i[2], time.time())) if len(handleRequestQueue) <= 0 and len(uuidRequestQueue) <= 0: logger.debug("Out of responses") break logger.debug("Number of responses that haven't received: %s" % (len(handleRequestQueue) + len(uuidRequestQueue))) gevent.sleep(0.1) return uuidRequests, handleRequests
def ble_handle_subscribe(address, handles, adapter, addressType, mode, listenTime=None): """ Used by command line tool to enable specified handles' notify mode and listen until user interrupts. :param address: Address of target BTLE device :param handles: List of handle descriptors to write 0100 (enable notification) to :param adapter: Host adapter (Empty string to use host's default adapter) :param addressType: Type of address you want to connect to [public | random] :param securityLevel: Security level [low | medium | high] :param mode: Mode to set for characteristic configuration (0=off,1=notifications,2=indications, 3=notifications and inidications) :type address: str :type handles: list of base 10 ints :type adapter: str :type addressType: str :type securityLevel: str :type mode: int :return: """ import time import gevent logger.debug("Beginning Subscribe Function") if address is None: raise Exception( "%s Bluetooth address is not valid. Please supply a valid Bluetooth address value." % address) if mode == 0: configVal = str(bytearray([00, 00])) elif mode == 1: configVal = str(bytearray([0o1, 00])) elif mode == 2: configVal = str(bytearray([0o2, 00])) elif mode == 3: configVal = str(bytearray([0o3, 00])) else: raise Exception( "%s is not a valid mode. Please supply a value between 0 and 3 (inclusive)" % mode) class EventHandler(event_handler.BTEventHandler): def __init__(self, connection_manager): event_handler.BTEventHandler.__init__(self, connection_manager) self.connectionManager = connection_manager def on_att_event(self, connection_handle, data): from blesuite.pybt.att import ATT_PDU_OPCODE_BY_NAME if data.opcode == 0x1b: #notification print("\nNotification on Handle %s" % hex(data.gatt_handle)) print("=======================") #print format(originHandle, "#8x") print_helper.print_data_and_hex([data.value], False) elif data.opcode == 0x1d: #indication print("\nIndication on Handle %s" % hex(data.gatt_handle)) print("=======================") print_helper.print_data_and_hex([data.value], False) with connection_manager.BLEConnectionManager( adapter, 'central') as connectionManager: connection = connectionManager.init_connection(address, addressType) success = connectionManager.connect(connection) if not success: print("Failed to connected to target device") return connectionManager.set_event_handler(EventHandler(connectionManager)) for handle in handles: connectionManager.gatt_write_handle(connection, int(handle, 16), configVal) start = time.time() * 1000 while True: if connectionManager.is_connected(connection): if listenTime is not None: if ((time.time() * 1000) - start) >= listenTime: break gevent.sleep(.1) continue logger.debug("Connection Lost, re-connecting subscribe") connectionManager.connect(connection) for i in handles: connectionManager.gatt_write_handle(connection, int(i, 16), configVal) if listenTime is not None: if ((time.time() * 1000) - start) >= listenTime: break gevent.sleep(.1)
def advertise(adapter, peripheral, data): with connection_manager.BLEConnectionManager( adapter, 'peripheral') as connectionManager: #peripheral, advertising_data_list = load_device(address) #ret = bdaddr.bdaddr(("hci"+str(adapter)), peripheral.address) #if ret == -1: # raise ValueError("Spoofing failed.") #else: # print "Address Spoofed." #local_name = "Name" #complete_local_name = "Name2" # Generate integer representation of advertisement data flags using helper function #flag_int = gap_utils.generate_ad_flag_value(le_general_discoverable=True, bredr_not_supported=True) # Generate advertisement data entry using helper function #flag_entry = gap_utils.advertisement_data_entry_builder("Flags", chr(flag_int)) # Generate advertisement data entry for shortened local name using helper function #short_local_name_entry = gap_utils.advertisement_data_entry_builder("Shortened Local Name", complete_local_name) # Generate advertisement data entry for complete local name using helper function #complete_local_name_entry = gap_utils.advertisement_data_entry_builder("Complete Local Name", local_name) # Build advertisement data list #ad_entries_list = [flag_entry, short_local_name_entry,complete_local_name_entry] # Build finalized advertisement data from list #ad_entries = gap_utils.advertisement_data_complete_builder(ad_entries_list) # Set advertising data sent in advertising packet #connectionManager.set_advertising_data(ad_entries) # Set data sent in response to an inquiry packet #connectionManager.set_scan_response_data(ad_entries) #connectionManager.set_local_name("MyFitnessTracker") # Set advertising parameters - advertising type, channel map, interval_min, interval_max, # destination address (only used if using directed advertising, just set to 00:00:00:00:00:00), # destination address type (only used if using directed advertising, set to 0x00 otherwise which is public) #connectionManager.set_advertising_parameters(gap_utils.gap.GAP_ADV_TYPES['ADV_IND'], 7, 0x0020, 0x00a0, # "00:00:00:00:00:00", 0x00) # Generate BLEDevice ble_device = BLEDevice() # Add Services and Characteristics to BLEDevice service1 = ble_device.add_service(0x01, 0x06, "2124") characteristic1 = service1.add_characteristic( 0x03, 0x02, "2124", Permissions.READ | Permissions.WRITE, "testValue1", characteristic_value_attribute_read_permission=att_utils. ATT_SECURITY_MODE_ENCRYPTION_NO_AUTHENTICATION, characteristic_value_attribute_write_permission=att_utils. ATT_SECURITY_MODE_ENCRYPTION_NO_AUTHENTICATION) characteristic1.add_user_description_descriptor( 0x04, "Characteristic 1") services = peripheral.get_services() connectionManager.initialize_gatt_server_from_ble_device( ble_device, True) gatt_server = connectionManager.get_gatt_server() gatt_server.debug_print_db() #connectionManager.start_advertising() result, ble_connection = connectionManager.advertise_and_wait_for_connection( ) if result: print "We are connected!" connectionManager.smart_scan(ble_connection, look_for_device_info=False, timeout=5) #data = "41542b424f4e443a4f4b0d0a".decode("hex") #handle = "0x0e" #connectionManager.gatt_write_handle_async(ble_connection,int(handle,0),data) gevent.sleep(50) else: print "Timeout reached. No one connected."
def advanced_peripheral(address, adapter, role): with connection_manager.BLEConnectionManager(adapter, role) as connectionManager: ''' Generate a GATT server for interaction by a Central device ''' # Generate BLEDevice # ble_device = BLEDevice() # # # Add Services and Characteristics to BLEDevice # service1 = ble_device.add_service(0x01, 0x06, "2124") # characteristic1 = service1.add_characteristic(0x03, 0x02, "2124", # Permissions.READ | Permissions.WRITE, # "testValue1", # characteristic_value_attribute_read_permission=att_utils.ATT_SECURITY_MODE_ENCRYPTION_NO_AUTHENTICATION, # characteristic_value_attribute_write_permission=att_utils.ATT_SECURITY_MODE_ENCRYPTION_NO_AUTHENTICATION # ) # characteristic1.add_user_description_descriptor(0x04, # "Characteristic 1") # per, data = load_device(address) # Generate GATT server on host using BLEDevice information. # 2nd param (True) tells the GATT import process to use attribute handles specified in the BLEDevice rather # than sequentially assigning them as attributes are added to the server connectionManager.initialize_gatt_server_from_ble_device(per, True) # Retrieve GATT server gatt_server = connectionManager.get_gatt_server() # Print GATT server for demonstration purposes gatt_server.debug_print_db() # Begin advertising and block until we are connected to a Central device (or until timeout is reached) result, ble_connection = connectionManager.advertise_and_wait_for_connection( ) if result: print "We are connected!" # After peer connects, quickly scan their gatt server and see what info is there ble_device = connectionManager.smart_scan( ble_connection, look_for_device_info=False, timeout=5) ble_device.print_device_structure() #Notification data1 = 0x41542b424f4e443a4f4b0d0a notify = connectionManager.gatt_write_handle( ble_connection, data1, "000b") #data2 = 0x # assuming we know a handle by this point, we can then start reading data # read from handle 0x0a read_request = connectionManager.gatt_read_handle( ble_connection, 0x3e) if read_request.has_error(): print "Got error:", read_request.get_error_message() elif read_request.has_response(): print "Got response:", read_request.response.data, "from handle", hex( read_request.handle)