async def connect(self, hub): self.message(f'Starting scan for UART {hub.uart_uuid}') # HACK try: ble_id = uuid.UUID(hub.ble_id) if hub.ble_id else None except ValueError: # In case the user passed in a self.message_info(f"ble_id {hub.ble_id} is not a parseable UUID, so assuming it's a BLE network addresss") ble_id = hub.ble_id await self._ble_connect(hub.uart_uuid, hub.ble_name, hub.manufacturer_id, ble_id) self.message(f"found device {self.device.name}") device = bleak.BleakClient(address=self.device.address) self.devices.append(device) await device.connect() hub.ble_id = self.device.address self.message_info(f'Device advertised: {device.services.characteristics}') hub.tx = (device, hub.char_uuid) # Hack to fix device name on Windows if self.device.name == "Unknown" and hasattr(device._requester, 'Name'): self.device.name = device._requester.Name self.message_info(f"Connected to device {self.device.name}:{hub.ble_id}") self.hubs[hub.ble_id] = hub await self.get_messages(hub)
async def connect(self, address, timeout=1): ''' Connects to device with given MAC address. The 'timeout' parameter specifices maximum time before giving up. ''' if not address: raise ValueError( 'Address is required. Please provide MAC address of target device' ) time_start = time.time() # Using Bleak as backend client = bleak.BleakClient(address) connected = False err = None attempt_num = 0 self.logger.info('connecting to device %s', address) while not connected and err is None: # Reattempts until timeout attempt_num = attempt_num + 1 self.logger.debug( 'attempting connection to device with address %s', address) try: await client.connect() connected = True except Exception as e: self.logger.debug("connection attempt #%d failed: %s", attempt_num, e) if time.time() - time_start < timeout: # Sleep 250ms between attempts await asyncio.sleep(0.25) else: err = e self.logger.warning('connection attempt timed out') if not connected: # Raise last exception when giving up raise err if err is not None else ValueError( 'connection failed in an unexpected way') self.logger.info('succesfully connected to device %s', address) self.connected = True self.bleak_client = client self.connected_address = address self.wrote_security_access = False # Profiles self.logger.debug('profiling the device') try: await self._profile_device() except Exception as e: self.logger.exception('error profiling device: %s', e) # Pings (reading a DeviceInfo register) to verify communication self.logger.debug('verifying communication layer') await self.ping() return self.bleak_client
async def asyncio_loop(self): # Wait for messages on in_queue done = False while not done: msg = await self.in_queue.get() if isinstance(msg, tuple): msg, val = msg await self.in_queue.task_done() if msg == 'discover': print('Awaiting on bleak discover') devices = await bleak.discover(timeout=1, loop=self.loop) print('Done Awaiting on bleak discover') await self.out_queue.put(devices) elif msg == 'connect': device = bleak.BleakClient(address=val, loop=self.loop) self.devices.append(device) await device.connect() await self.out_queue.put(device) elif msg == 'tx': device, char_uuid, msg_bytes = val await device.write_gatt_char(char_uuid, msg_bytes) elif msg == 'notify': device, char_uuid, msg_handler = val await device.start_notify(char_uuid, msg_handler) elif msg == 'quit': print("quitting") logging.info('quitting') for device in self.devices: await device.disconnect() done = True print("quit") else: print(f'Unknown message to Bleak: {msg}')
async def get_device_services(device): try: async with bleak.BleakClient(device.address) as server: services = await server.get_services() except bleak.exc.BleakError: services = None return device, services
async def example(self): while self.running: try: self.line("scanning") scanned_devices = await bleak.BleakScanner.discover(1) self.line("scanned", True) if len(scanned_devices) == 0: raise bleak.exc.BleakError("no devices found") scanned_devices.sort(key=lambda device: -device.rssi) for device in scanned_devices: self.line(f"{device.name} {device.rssi}dB") for device in scanned_devices: self.line(f"Connecting to {device.name} ...") try: async with bleak.BleakClient(device) as client: services = await client.get_services() for service in services.services.values(): self.line(f" service {service.uuid}") for characteristic in service.characteristics: self.line( f" characteristic {characteristic.uuid} {hex(characteristic.handle)} ({len(characteristic.descriptors)} descriptors)" ) except bleak.exc.BleakError as e: self.line(f" error {e}") asyncio.sleep(10) except bleak.exc.BleakError as e: self.line(f"ERROR {e}") await asyncio.sleep(1) self.line("example loop terminated", True)
async def run(addr, host): async with asyncio_mqtt.Client(host) as mqtt: async with bleak.BleakClient(addr) as dev: svcs = await dev.get_services() for char in svcs.characteristics.values(): if char.uuid.startswith('0000ffe1'): light_char = char break else: print('not found') return print(light_char) topic = 'led/{}/rgb'.format(addr) print(topic) async with mqtt.filtered_messages(topic) as msgs: await mqtt.subscribe(topic) async for msg in msgs: rgb_str = msg.payload.decode() print(rgb_str) parts = [int(n) for n in rgb_str.split()] for val in parts: assert 0 <= val <= 255 r, g, b = parts data = bytearray([r, g, b, 0x1e]) await dev.write_gatt_char(light_char, data)
async def open_bluetooth_cli(device_name='Project21', rx_uuid='6e400002-b5a3-f393-e0a9-e50e24dcca9e', tx_uuid='6e400003-b5a3-f393-e0a9-e50e24dcca9e', *, log=print): """opens cli with bluetooth device as async coroutine first iteration will connect to the device and yield initial prompt from device subsequently should call .asend(message) to send the message to the device this will read the output and produce it as a response to the asend call. """ device = await scan_for_device(device_name, log=log) is_connected = True def device_has_disconnected(c=None): nonlocal is_connected log("BLUETOOTH DEVICE DISCONNECTED") is_connected = False log("BEFORE WITH") async with bleak.BleakClient(device.address) as client: log("INSIDE WITH") client.set_disconnected_callback(device_has_disconnected) # TODO: check this makes sense once I can actually test it. while is_connected: output_from_device = await client.read_gatt_char(rx_uuid) msg_send_to_device = yield output_from_device await client.write_gatt_char(tx_uuid, msg_send_to_device.encode()) log("closed connection with bluetooth device")
async def read_data(address, done, handler): async with bleak.BleakClient(address) as client: x = await client.is_connected() print("Connected: {0}".format(x)) notification_handler = make_handler(handler) await client.start_notify(CHARACTERISTIC_UUID, notification_handler) await done.wait() print('Disconnecting ...')
async def device(self, address): try: client = bleak.BleakClient(address) await client.connect() device = LEDevice(self, address, client) self._connected.append(device) return device except Exception as e: print('== failed to connect to {} =='.format(address), e) return None
async def connect(loop, address, uuid): async with bleak.BleakClient(address, loop=loop, timeout=args.timeout) as client: message = await client.read_gatt_char(uuid, timeout=args.timeout) now = datetime.datetime.now().isoformat() if args.json: #soooo deeeeep . what is pep8? data = {"time": now, "data": message.decode(), "address": address} print(json.dumps(data)) else: print(f'[{now}] {address} : {message.decode()}')
def __init__(self, address, name=None, *args, default_timeout=DEFAULT_TIMEOUT): import bleak self._address = address self._name = name self._client = bleak.BleakClient(self._address) self._default_timeout = DEFAULT_TIMEOUT
def __init__(self, address): self.__event_loop = asyncio.new_event_loop() self.__device = bleak.BleakClient(address, loop=self.__event_loop, timeout=5.0) self.__lock = threading.Lock() self.__thread = threading.Thread(target=self.__event_loop.run_forever) self.__thread.start() try: self.__execute(self.__device.connect()) except: self.close(False) raise
def __init__(self, address, name=None, *args, default_timeout=DEFAULT_TIMEOUT): import bleak self._address = address self._name = name self._client = bleak.BleakClient(self._address) self._notification_queue = asyncio.Queue(maxsize=1) self._default_timeout = DEFAULT_TIMEOUT
async def connect(self, timeout=2, retries=None) -> bool: """Connect to the specified GATT server. Returns: Boolean representing connection status. """ if self.client is not None: try: if await asyncio.wait_for(self.is_connected(), self.timeout): self.logger.debug("Devices is already connected.") return True except Exception as e: self.logger.error( f"[BleClient.{currentFuncName()}] received exception: " + str(e)) if retries is None: retries = self.maxretries for i in range(0, retries): try: self.client = bleak.BleakClient(self.address, self.loop) # Overrides the bleak connect method # self.client.connect = types.MethodType( new_bleak_client_connect.connect, self.client) t1 = time.perf_counter() status = await asyncio.wait_for( self.client.connect(timeout=timeout), self.timeout) t2 = time.perf_counter() - t1 self.logger.info( f"[BleClient.{currentFuncName()}] connection established in {round(t2,2)}s in {i+1} of {retries} tries." ) return status except Exception as e: del self.client self.client = None if (i + 1) < retries: self.logger.warning( f"[BleClient.{currentFuncName()}] failed to connect in {str(i+1)} of {str(retries)} tries." + " Received exception: " + str(e)) else: self.logger.error( f"[BleClient.{currentFuncName()}] could not connect to device." + " Received exception: " + str(e)) raise e
def __init__(self, *args: object, adapter: Optional[str] = None, **kwargs: object): """ Initialization of an instance of a remote RadonEye RD200 :param address_or_ble_device: The Bluetooth address of the BLE peripheral to connect to or the `BLEDevice` object representing it. """ # Can't pass adapter=None to BleakClient if adapter is not None: kwargs.update(adapter=adapter) self.device = bleak.BleakClient(*args, **kwargs) self._ctl: Optional[BleakGATTCharacteristic] = None self._meas: Optional[BleakGATTCharacteristic] = None self._log: Optional[BleakGATTCharacteristic] = None
def __init__( self, target: Union[str, PranaDeviceInfo], loop: Optional[AbstractEventLoop] = None, iface: str = "hci0", ) -> None: self.__address = None if isinstance(target, PranaDeviceInfo): self.__address = target.address elif isinstance(target, str): self.__address = target else: raise ValueError( "PranaDevice constructor error: Target must be either mac address or PranaDeviceInfo instance" ) self.__client = bleak.BleakClient(self.__address, device=iface) self.__has_connect_attempts = False self.__notification_bytes: Optional[bytearray] = None self.__state: Optional[PranaState] = None self.__read_state_event: Optional[asyncio.Event] = None self.__lock = Lock() self.__logger = logging.getLogger(self.__class__.__name__)
async def run_session(self): """ Connecting to the device that is associated with the given MAC address, configuring the resistance level of the workout, starting the workout session and reading data from the bike every second until it is finished. """ try: loop = asyncio.get_event_loop() async with bleak.BleakClient(self.address, loop=loop) as self.client: await self.initialize_session() time.sleep(1) await self.set_level(self.workout_session.program.level) time.sleep(1) # Starting the workout session. await self.client.write_gatt_char(self.characteristic_uuid, START) time.sleep(1) while not self.stop_flag: # Stopping the session if the session is out of time. if self.current_minute == self.workout_session.program.duration: break # Reading the current data from the exercise bike. await self.client.write_gatt_char(self.characteristic_uuid, READ) # Changing the resistance level if the chosen workout program specifies it. if self.current_minute < self.workout_session.program.duration: new_level = self.workout_session.program.levels[self.current_minute] if self.current_level != new_level: await self.set_level(new_level) self.current_level = new_level time.sleep(1) await self.stop_session() except bleak.BleakError as e: print(f"Bleak raised an exception: {e}") await self.run_session()
async def get_writeable_uuid(self, address, loop): """ Looping through the characteristics of the given device and saving the uuid if a writeable characteristic is found. In this context "writeable" is defined as returning the correct notification when a READ packet is written to the characteristic, meaning that the given device is a viable exercise bike. :param address: The MAC address of the BLE device that should be checked for writeable characteristics. :param loop: The event loop used to connect to the device. """ try: async with bleak.BleakClient(address, loop=loop) as client: services = await client.get_services() for key, value in services.characteristics.items(): try: await client.start_notify(value.uuid, self.notification_handler) time.sleep(0.5) await client.write_gatt_char(value.uuid, READ) except bleak.BleakError as e: print(f"Bleak raised an exception: {e}") except bleak.BleakError as e: print(f"Bleak raised an exception: {e}") await self.get_writeable_uuid(address, loop)
def AV_ble_client(address_p="3C:71:BF:FD:31:EA"): return bleak.BleakClient(address_p)
async def connect_to_device(self, loop): print("starting", self.smartrowdevice.address, "loop") async with bleak.BleakClient(self.smartrowdevice.address, timeout=5.0) as client: print("connect to", self.smartrowdevice.address)
def get_client(device): return bleak.BleakClient(device)
async def run_all_devices(debug=False): if debug: import sys # loop.set_debug(True) l = logging.getLogger("asyncio") l.setLevel(logging.DEBUG) h = logging.StreamHandler(sys.stdout) h.setLevel(logging.DEBUG) l.addHandler(h) logger.addHandler(h) x = await bleak.BleakScanner.discover() l.info("*********** Start of discovered list *************") i = 1 for d in x: #l.info(d) #l.info(bleak.utils.mac_str_2_int(d.address)) print("[{0}] ".format(i) + d.address + " " + d.name) i += 1 if i >= 10: break #if d.address == TARGET_ADDRESS: # await found_unit(d) l.info("*********** End of discovered list ***************") print("Enter number to connect (or anything else to cancel):") s = input() try: j_s = int(s) except ValueError: j_s = -1 if j_s > 0 and j_s <= len(x): # a good value! async with bleak.BleakClient(x[j_s - 1].address) as client: y = await client.is_connected() l.info("Connected: {0}".format(y)) w = await client.get_services() w_serv = w.get_service(CONFIG_SERVICE_UUID.lower()) l.info(w_serv) w_char = [ w.get_characteristic(CONFIG_1_CHAR_UUID.lower()), w.get_characteristic(CONFIG_2_CHAR_UUID.lower()), w.get_characteristic(CONFIG_3_CHAR_UUID.lower()) ] l.info(w_char[0].service_uuid) l.info(w_char[0]) l.info(w_char[1].service_uuid) l.info(w_char[1]) l.info(w_char[2].service_uuid) l.info(w_char[2]) t_0 = await client.read_gatt_char(w_char[0]) t_1 = await client.read_gatt_char(w_char[1]) t_2 = await client.read_gatt_char(w_char[2]) print(t_0) print(t_1) print(t_2) is_central = False if len(t_0) >= 1: is_central = ((t_0[0] & 0x01) != 0) if is_central: print("This is a central device. Choose:") print("[1] change to peripheral") print("[2] no change (remain as central)") s = input() try: k_s = int(s) except ValueError: k_s = 2 if k_s == 1: await client.write_gatt_char(w_char[0], bytearray(b'\x00')) is_central = False print("Changed") else: print("This is a peripheral device. Choose:") print("[1] no change (remain as peripheral)") print("[2] change to central") s = input() try: k_s = int(s) except ValueError: k_s = 1 if k_s == 2: await client.write_gatt_char(w_char[0], bytearray(b'\x01')) print("Changed") is_central = True if len(t_1) >= 4 and is_central: val_2 = struct.unpack('<I', t_1)[0] print("This is a central device with trigger threshold {0}.". format(0x3FFF & val_2)) print("Enter a new value, or <Enter> to keep old one:") s = input() try: k_s = int(s) except ValueError: k_s = -1 if k_s >= 0: new_val = (val_2 & 0xFFFFC000) | (k_s & 0x3FFF) await client.write_gatt_char( w_char[1], bytearray(struct.pack('<I', new_val))) print("Changed") else: print("No change") z = await client.disconnect() logger.info("Disconnected: {0}".format(z)) await asyncio.sleep(1.0) await asyncio.sleep(1.0)
async def run_specific_device_leaf(addr, debug=False): global rxed_data global rxed_data_2 global dev_list global do_dev_list global is_leaf_locked global trigger_size if debug: import sys # loop.set_debug(True) l = logging.getLogger("asyncio") l.setLevel(logging.DEBUG) h = logging.StreamHandler(sys.stdout) h.setLevel(logging.DEBUG) l.addHandler(h) logger.addHandler(h) # Do an initial connection to wake it up #async with bleak.BleakClient(addr) as client: # x = await client.is_connected() # l.info("Connected: {0}".format(x)) #await asyncio.sleep(40.0) # Now do the connection where we lock and read data async with bleak.BleakClient(addr) as client: x = await client.is_connected() l.info("Connected: {0}".format(x)) y = await client.get_services() y_serv = y.get_service(SERVICE_UUID.lower()) l.info(y_serv) y_char = y.get_characteristic(READ_CHAR_UUID.lower()) l.info(y_char) l.info(y_char.service_uuid) await client.start_notify(READ_CHAR_UUID, notification_handler_leaf) if False: #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__IDENTIFY_SELF, 0))) # no data, just send 0 #await asyncio.sleep(2.0) await client.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__QUERY_IS_SYNCED, 0))) # no data, just send 0 await asyncio.sleep(0.2) else: # #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0xe,0,0,0,0xff,0xff,0xff,0xff])) await client.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__QUERY_IS_SYNCED, 0))) # no data, just send 0 await asyncio.sleep(0.2) await client.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__QUERY_CURRENT_TIME, 0))) # no data, just send 0 await asyncio.sleep(0.2) await client.write_gatt_char( WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED, 0))) # no data, just send 0 await asyncio.sleep(0.2) #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__LOCK, 0xFFFFFFFF))) # 0xFFFFFFFF means current time #await asyncio.sleep(0.4) await client.write_gatt_char( WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED, 0))) # no data, just send 0 await asyncio.sleep( 5.) # Need to give sufficient time for the buffer to fill up. # If not sufficient, nothing will be returned rxed_data = b'' #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__READ_OUT, 0))) # no data, just send 0 #await asyncio.sleep(0.2) a = 0 kk = 0 while a < 1000: await asyncio.sleep(1.0) if do_dev_list: do_dev_list = False for dd in dev_list: async with bleak.BleakClient(dd) as client_2: x_2 = await client.is_connected() l.info("Connected: {0}".format(x_2)) await client_2.start_notify( READ_CHAR_UUID, notification_handler_leaf_2) await asyncio.sleep(1.2) await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__QUERY_IS_SYNCED, 0))) # no data, just send 0 await asyncio.sleep(0.2) await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack( '<2I', INSTRUCTION_CODE__QUERY_CURRENT_TIME, 0))) # no data, just send 0 await asyncio.sleep(0.2) await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED, 0))) # no data, just send 0 await asyncio.sleep(0.4) await client_2.stop_notify(READ_CHAR_UUID) z_2 = await client_2.disconnect() l.info("Disconnected: {0}".format(z_2)) if trigger_size > 0: with open("Trigger_list.txt", "a") as f3: f3.write(datetime.datetime.now().strftime( "%Y/%m/%d %H:%M:%S ") + "{0} {1}\n".format(trigger_size, len(dev_list))) trigger_size = 0 for dd in dev_list: async with bleak.BleakClient(dd) as client_2: x_2 = await client.is_connected() l.info("Connected: {0}".format(x_2)) await client_2.start_notify( READ_CHAR_UUID, notification_handler_leaf_2) await asyncio.sleep(1.2) await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__QUERY_IS_SYNCED, 0))) # no data, just send 0 await asyncio.sleep(0.2) await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack( '<2I', INSTRUCTION_CODE__QUERY_CURRENT_TIME, 0))) # no data, just send 0 await asyncio.sleep(0.2) is_leaf_locked = False await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED, 0))) # no data, just send 0 await asyncio.sleep(0.4) if is_leaf_locked: rxed_data_2 = b'' await client_2.write_gatt_char( WRITE_CHAR_UUID, bytearray( struct.pack('<2I', INSTRUCTION_CODE__READ_OUT, 0))) # no data, just send 0 await asyncio.sleep(5.2) if len(rxed_data_2) > 0: with open( datetime.datetime.now().strftime( "%Y%m%d_%H%M%S_") + "{0:03d}_".format(kk) + dd + ".bin", "wb") as f1: f1.write(rxed_data_2) await client_2.stop_notify(READ_CHAR_UUID) z_2 = await client_2.disconnect() l.info("Disconnected: {0}".format(z_2)) kk += 1 a += 1 # Now save any data that has been received if len(rxed_data) > 0: with open(datetime.datetime.now().strftime("%Y%m%d_%H%M%S.bin"), "wb") as f1: f1.write(rxed_data) with open(datetime.datetime.now().strftime("%Y%m%d_%H%M%S.txt"), "w") as f1: i = 0 j = 0 while i + 8 <= len(rxed_data): tt = struct.unpack('<4h', rxed_data[i:i + 8]) f1.write("{0},{1},{2},{3},{4}\n".format( j, tt[0], tt[1], tt[2], tt[3])) i += 8 j += 1 rxed_data = b'' await client.stop_notify(READ_CHAR_UUID) z = await client.disconnect() logger.info("Disconnected: {0}".format(z)) await asyncio.sleep(1.0)
async def found_unit(dev): await asyncio.sleep(1.0) async with bleak.BleakClient(dev.address) as client: svcs = await client.get_services() print("Services:", svcs.services)
def __new_client(self) -> bleak.BleakClient: return bleak.BleakClient(self.__address, device=self.__iface)
async def main(): print("Connecting to", DEVICE_MAC, file=sys.stderr) async with bleak.BleakClient(DEVICE_MAC) as client: tasks = [asyncio.ensure_future(run(client))] await asyncio.gather(*tasks)
async def _connect_impl(self): assert self.client is None # Input received, buffered awaiting external read inbufs = collections.deque() # Async stream of those items for reading async def _input_stream(): # Poll for new input all the time client exists while self.client is not None: while inbufs: buf = inbufs.popleft() for b in buf: yield b # No data, yield to event loop awaiting arrival of more data await asyncio.sleep(0.01) # Stream drained and client connection no longer exists self.inputstream = None self.inputstream = _input_stream() # Scan for expected ble device # Match device-name only if no serial number provided device_mac = None while not device_mac and self.scan_timeout > 0: logger.info("Scanning, timeout = {}s".format(self.scan_timeout)) scan_time = min(2, self.scan_timeout) self.scan_timeout -= scan_time devices = await bleak.discover(scan_time) for dev in devices: logger.debug('Seen: {}'.format(dev.name)) if dev.name and \ dev.name.startswith(self.device_name) and \ (self.serial_number is None or dev.name.endswith(self.serial_number)): # Map pretty name to mac-type address device_mac = dev.address full_name = dev.name if not device_mac: raise JadeError(1, "Unable to locate BLE device", "Device name: {}, Serial number: {}".format( self.device_name, self.serial_number or '<any>')) # Remove previous bt/ble pairing data for this device if platform.system() == 'Linux': command = "bt-device --remove '{}'".format(device_mac) process = subprocess.run(command, shell=True, stdout=subprocess.DEVNULL) # Connect - seems pretty flaky so allow retries connected = False attempts_remaining = 3 while not connected: try: attempts_remaining -= 1 client = bleak.BleakClient(device_mac) logger.info('Connecting to: {} ({})' .format(full_name, device_mac)) await client.connect() connected = await client.is_connected() logger.info('Connected: {}'.format(connected)) except Exception as e: logger.warn("BLE connection exception: '{}'".format(e)) if not attempts_remaining: logger.warn("Exhausted retries - BLE connection failed") raise # Peruse services and characteristics for service in client.services: for char in service.characteristics: if 'read' in char.properties: await client.read_gatt_char(char.uuid) for descriptor in char.descriptors: await client.read_gatt_descriptor(descriptor.handle) # Attach handler to be notified of new data def _notification_handler(characteristic, data): assert characteristic == JadeBleImpl.IO_RX_CHAR_UUID inbufs.append(data) await client.start_notify(JadeBleImpl.IO_RX_CHAR_UUID, _notification_handler) # Attach handler to catch unexpected disconnection def _disconnection_handler(client): logger.error("Unexpected BLE disconnection") # Set the client to None - that will cause the receive # generator to terminate and not wait forever for data. assert client == self.client self.client = None # Also cancel any running task trying to write data, # as otherwise that hangs forever too ... if self.write_task: self.write_task.cancel() self.write_task = None client.set_disconnected_callback(_disconnection_handler) # Done self.client = client
def __init__(self, address): self._address = address self._client = bleak.BleakClient(address)
async def run_specific_device(addr, debug=False): if debug: import sys # loop.set_debug(True) l = logging.getLogger("asyncio") l.setLevel(logging.DEBUG) h = logging.StreamHandler(sys.stdout) h.setLevel(logging.DEBUG) l.addHandler(h) logger.addHandler(h) async with bleak.BleakClient(addr) as client: x = await client.is_connected() l.info("Connected: {0}".format(x)) y = await client.get_services() y_serv = y.get_service(SERVICE_UUID.lower()) l.info(y_serv) y_char = y.get_characteristic(READ_CHAR_UUID.lower()) l.info(y_char) l.info(y_char.service_uuid) #c_serv = y.get_service(CONFIG_SERVICE_UUID.lower()) #l.info(c_serv) #c_char = y.get_characteristic(CONFIG_3_CHAR_UUID.lower()) #l.info(c_char) #l.info(c_char.service_uuid) char_1_val = await client.read_gatt_char(CONFIG_1_CHAR_UUID.lower()) print("Char 1 Value: 0x{0:04X}".format(char_1_val[0])) print("Char 1 length: {0}".format(len(char_1_val))) char_2_val = await client.read_gatt_char(CONFIG_2_CHAR_UUID.lower()) print("Char 2 Value: 0x{0:02X} {1:02X} {2:02X} {3:02X}".format( char_2_val[0], char_2_val[1], char_2_val[2], char_2_val[3])) print("Char 2 length: {0}".format(len(char_2_val))) char_3_val = await client.read_gatt_char(CONFIG_3_CHAR_UUID.lower()) print("Char 3 Value: 0x{0:04X}".format(char_3_val[0])) print("Char 3 length: {0}".format(len(char_3_val))) if False: x = bytearray(randbytes(1)) print("Writing Char1 to 0x{0:02X}".format(x[0])) await client.write_gatt_char(CONFIG_1_CHAR_UUID, x) x = bytearray(randbytes(4)) print("Writing Char2 to 0x{0:02X} {1:02X} {2:02X} {3:02X}".format( x[0], x[1], x[2], x[3])) await client.write_gatt_char(CONFIG_2_CHAR_UUID, x) await asyncio.sleep(0.6) print("Done") await client.start_notify(READ_CHAR_UUID, notification_handler) # #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0xe,0,0,0,0xff,0xff,0xff,0xff])) #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0x21,0,0,0,0,0,0,0])) #await asyncio.sleep(0.2) #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0x0E,0,0,0,0,0,0,0])) await asyncio.sleep(25.0) await client.stop_notify(READ_CHAR_UUID) z = await client.disconnect() logger.info("Disconnected: {0}".format(z)) await asyncio.sleep(1.0)
async def process_connection(reader: asyncio.streams.StreamReader, writer: asyncio.streams.StreamWriter): peer = writer.get_extra_info('peername') def callback(char, d): if writer.is_closing(): return char = char.encode('ascii') writer.write(ResponseOp.ON_DATA + to_bytes(len(char), 2) + char + to_bytes(len(d), 1) + d) asyncio.ensure_future(writer.drain()) print('Incoming connection from %s:%d' % peer) adapter: Optional[bleak.BleakClient] = None try: while True: cmd = await reader.readexactly(1) if cmd == RequestOp.SCAN: timeout = struct.unpack('!f', await reader.readexactly(4))[0] try: toys = await bleak.discover(timeout) except BaseException as e: err = str(e)[:0xffff].encode('utf_8') writer.write(ResponseOp.ERROR + to_bytes(len(err), 2) + err) await writer.drain() continue writer.write(ResponseOp.OK + to_bytes(len(toys), 2)) await writer.drain() for toy in toys: name = toy.name.encode('utf_8') addr = toy.address.encode('ascii') writer.write(to_bytes(len(name), 2) + name + to_bytes(len(addr), 2) + addr) await writer.drain() elif cmd == RequestOp.END: break else: seq_size = await reader.readexactly(3) seq, size = seq_size[0], to_int(seq_size[1:]) data = (await reader.readexactly(size)).decode('ascii') try: if cmd == RequestOp.INIT: adapter = bleak.BleakClient(data, timeout=5.0) await adapter.connect() elif cmd == RequestOp.SET_CALLBACK: await adapter.start_notify(data, callback) elif cmd == RequestOp.WRITE: size = to_int(await reader.readexactly(2)) payload = bytearray(await reader.readexactly(size)) await adapter.write_gatt_char(data, payload, True) except EOFError: raise except BaseException as e: err = str(e)[:0xffff].encode('utf_8') writer.write(ResponseOp.ERROR + to_bytes(len(err), 2) + err + bytes([seq])) await writer.drain() continue writer.write(ResponseOp.OK + bytes([seq])) await writer.drain() finally: writer.close() if adapter and await adapter.is_connected(): await adapter.disconnect() await writer.wait_closed() print('Disconnected from %s:%d' % peer)