async def find_ble_device(name, timeout=5): """Quickly find BLE device address by friendly device name. This is an alternative to bleak.discover. Instead of waiting a long time to scan everything, it returns as soon as it finds any device with the requested name. Arguments: name (str): Friendly device name. timeout (float): When to give up searching. Returns: str: Matching device address. Raises: TimeoutError: Device was not found within the timeout. """ # Flag raised by detection of a device device_discovered = False def set_device_discovered(*args): nonlocal device_discovered device_discovered = True # Create scanner object and register callback to raise discovery flag scanner = BleakScanner() scanner.register_detection_callback(set_device_discovered) # Start the scanner await scanner.start() INTERVAL = 0.1 # Sleep until a device of interest is discovered. We cheat by using the # cross-platform get_discovered_devices() ahead of time, instead of waiting # for the whole discover() process to complete. We call it every time # a new device is detected by the register_detection_callback. for i in range(round(timeout / INTERVAL)): # If device_discovered flag is raised, check if it's the right one. if device_discovered: # Unset the flag so we only check if raised again. device_discovered = False # Check if any of the devices found so far has the expected name. devices = await scanner.get_discovered_devices() for dev in devices: # If the name matches, stop scanning and return address. if name == dev.name: await scanner.stop() return dev.address # Await until we check again. await asyncio.sleep(INTERVAL) # If we are here, scanning has timed out. await scanner.stop() raise TimeoutError("Could not find {0} in {1} seconds".format( name, timeout))
async def run(): scanner = BleakScanner() scanner.register_detection_callback(detection_callback) while True: await scanner.start() await asyncio.sleep(0.5) await scanner.stop()
async def connect_and_send(data): scanner = BleakScanner() scanner.register_detection_callback(detect_printer) await scanner.start() for x in range(50): await asyncio.sleep(0.1) if device: break await scanner.stop() if not device: raise BleakError(f"No device named GB01 could be found.") async with BleakClient(device) as client: # Set up callback to handle messages from the printer await client.start_notify(NotifyCharacteristic, notification_handler) while (data): # Cut the command stream up into pieces small enough for the printer to handle await client.write_gatt_char(PrinterCharacteristic, data[:PacketLength]) data = data[PacketLength:] while not transmit: # Pause transmission per printer request. # Note: doing it this way does not appear to actually work. await asyncio.sleep(0)
async def scan_devices_task(self): empty_scans = 0 while True: # 10 empty scans in a row means that bluetooth restart is required if empty_scans >= 10: empty_scans = 0 await restart_bluetooth() try: async with handle_ble_exceptions(): scanner = BleakScanner() scanner.register_detection_callback( self.device_detection_callback, ) try: await aio.wait_for(scanner.start(), 10) except aio.TimeoutError: _LOGGER.error('Scanner start failed with timeout') await aio.sleep(3) devices = scanner.discovered_devices await scanner.stop() if not devices: empty_scans += 1 else: empty_scans = 0 _LOGGER.debug(f'found {len(devices)} devices: {devices}') except KeyboardInterrupt: raise except aio.IncompleteReadError: raise except ListOfConnectionErrors as e: _LOGGER.exception(e) empty_scans += 1 await aio.sleep(1)
async def run(): scanner = BleakScanner() scanner.register_detection_callback(detection_callback) await scanner.start() await asyncio.sleep(float(60)) await scanner.stop() devices = await scanner.get_discovered_devices()
async def update(): scanner = BleakScanner(filter={'DuplicateData':False}) scanner.register_detection_callback(accelerometer_callback) while True: await scanner.start() await asyncio.sleep(5) await scanner.stop()
def __init__(self, settings: EncryptionSettings, bleAdapterAddress: str = None): # bleAdapterAddress is the MAC address of the adapter you want to use. self.settings = settings self.bleAdapterAddress = bleAdapterAddress # Connection self.activeClient: ActiveClient or None = None # Scanning self.scanner = BleakScanner(adapter=bleAdapterAddress) self.scanningActive = False self.scanAborted = False scanDelegate = BleakScanDelegate(self.settings) self.scanner.register_detection_callback(scanDelegate.handleDiscovery) # Event bus self.subscriptionIds = [] self.validator = Validator() self.subscriptionIds.append( BleEventBus.subscribe(SystemBleTopics.abortScanning, lambda x: self.abortScan())) # To be moved to active client or notification handler. self.notificationLoopActive = False
async def main(): scanner = BleakScanner() scanner.register_detection_callback(simple_callback) while True: await scanner.start() await asyncio.sleep(5.0) await scanner.stop()
async def scan(): scanner = BleakScanner() scanner.register_detection_callback(detection_callback) await scanner.start() await asyncio.sleep(3.0) await scanner.stop() return await scanner.get_discovered_devices()
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Fjäråskupan from a config entry.""" scanner = BleakScanner() state = EntryState(scanner, {}) hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = state async def detection_callback( ble_device: BLEDevice, advertisement_data: AdvertisementData) -> None: if not device_filter(ble_device, advertisement_data): return _LOGGER.debug("Detection: %s %s - %s", ble_device.name, ble_device, advertisement_data) data = state.devices.get(ble_device.address) if data: data.device.detection_callback(ble_device, advertisement_data) data.coordinator.async_set_updated_data(data.device.state) else: device = Device(ble_device) device.detection_callback(ble_device, advertisement_data) async def async_update_data(): """Handle an explicit update request.""" await device.update() return device.state coordinator: DataUpdateCoordinator[State] = DataUpdateCoordinator( hass, logger=_LOGGER, name="Fjaraskupan Updater", update_interval=timedelta(seconds=120), update_method=async_update_data, ) coordinator.async_set_updated_data(device.state) device_info: DeviceInfo = { "identifiers": {(DOMAIN, ble_device.address)}, "manufacturer": "Fjäråskupan", "name": "Fjäråskupan", } device_state = DeviceState(device, coordinator, device_info) state.devices[ble_device.address] = device_state async_dispatcher_send(hass, f"{DISPATCH_DETECTION}.{entry.entry_id}", device_state) scanner.register_detection_callback(detection_callback) await scanner.start() hass.config_entries.async_setup_platforms(entry, PLATFORMS) return True
async def run(): global start scanner = BleakScanner() scanner.register_detection_callback(detection_callback) start = time.time() await scanner.start() await asyncio.sleep(float(duration)) await scanner.stop() end = time.time()
async def run(): # https://github.com/hbldh/bleak/issues/230#issuecomment-652822031 # scanner = BleakScanner(AdvertisementFilter=) scanner = BleakScanner(filter={'DuplicateData': False}) scanner.register_detection_callback(accelerometer_callback) while True: await scanner.start() await asyncio.sleep(5) await scanner.stop()
async def start(self): def _callback(device: BLEDevice, adv: AdvertisementData): adv = process_advertisement(device, adv) if adv: for callback in self._callbacks: callback(adv.dict()) scanner = BleakScanner() scanner.register_detection_callback(_callback) await scanner.start()
async def run(): scanner = BleakScanner() scanner.register_detection_callback(detection_callback) await scanner.start() await asyncio.sleep(2.0) await scanner.stop() devices = await scanner.get_discovered_devices() for d in devices: print(d)
async def asyncRun(self, loop): scanner = BleakScanner() scanner.register_detection_callback(self.detection_handler) await scanner.start() print('scanning...') while not self.__found: await asyncio.sleep(0.2) await scanner.stop() print('scanning...done')
async def main(): scanner = BleakScanner() # print('scanner: created') scanner.register_detection_callback(detection_callback) # print('scanner: registered') await scanner.start() # print('scanner: started') await asyncio.sleep(5.0) # print('wait end') await scanner.stop() # print('scanner: stopped') print(json.dumps(meters))
async def asyncRun(): global found scanner = BleakScanner() scanner.register_detection_callback(detection_handler) await scanner.start() print('scanning...') while not found: await asyncio.sleep(0.2) await scanner.stop() print('scanning...done')
async def list(self, timeout=5) -> list: # logger.debug("list devices...") self.devices_list = {} # 清空 try: scanner = BleakScanner() self.scanner = scanner scanner.register_detection_callback(self._detection_ble_callback) await scanner.start() await asyncio.sleep(5.0) await self.scanner.stop() except BleakError as e: # 提醒开启蓝牙 logger.error(e) await self.node_instance.pub_notification(str(e), type="ERROR") return []
async def find_device(name: str, timeout: float = 5) -> BLEDevice: """Quickly find BLE device address by friendly device name. This is an alternative to bleak.discover. Instead of waiting a long time to scan everything, it returns as soon as it finds any device with the requested name. Arguments: name (str): Friendly device name. timeout (float): When to give up searching. Returns: BLEDevice: Matching device. Raises: asyncio.TimeoutError: Device was not found within the timeout. """ print("Searching for {0}".format(name)) queue = asyncio.Queue() def set_device_discovered(device: BLEDevice, _: AdvertisementData): if device.name != name: return queue.put_nowait(device) async with BleakScanner(detection_callback=set_device_discovered): return await asyncio.wait_for(queue.get(), timeout=timeout)
async def find_known_device_by_address(device_identifier: str, timeout: float = 10.0 ) -> Optional[Device]: """Find a device (with metadata) by Bluetooth address or UUID address (macOS).""" device_identifier = device_identifier.lower() stop_scanning_event = asyncio.Event() def stop_if_detected(device: BLEDevice, advertisement: AdvertisementData): if device.address.lower( ) == device_identifier and determine_known_device( device, advertisement): stop_scanning_event.set() async with BleakScanner( timeout=timeout, detection_callback=stop_if_detected) as scanner: try: await asyncio.wait_for(stop_scanning_event.wait(), timeout=timeout) except asyncio.TimeoutError: return None device = next( determine_known_device(d) for d in await scanner.get_discovered_devices() if d.address.lower() == device_identifier) return device
def __init__(self): self.ble_queue = queue.Queue() self.message_queue = queue.Queue() self.message_thread = threading.Thread( name="QueueThread", target=BasePlugin.handle_message, args=(self, )) self.ble_thread = threading.Thread(name="BleThread", target=BasePlugin.handle_ble, args=(self, )) self.keeping_track = {} self.scanner = BleakScanner() self.scanner.register_detection_callback(self.simple_callback) self.loop = asyncio.get_event_loop() self.macs = []
async def _scan(loop): # Wrapped function for detection_callback def _wrapped(sender, eventargs): try: res = self._detection_callback(sender, eventargs, distinct) except SkipData: pass else: try: callback(res) except Exception as e: traceback.print_exc() def _wrapped_Linux(scanner): def _wrapped(msg): self._detection_callback_Linux(scanner, msg, callback, distinct) return _wrapped # Scan rsp can be obtained with active scan if active: kw = {} # Active scan (for 0x03, 0x04) else: kw = {"scanning_mode": "passive"} # Passive scan(default) async with BleakScanner(loop=loop, **kw) as scanner: if platform.system() == "Linux": # NOTE: Bluez 5.50 may not return all every received messages. # Data seems to be detected every 11 seconds. # In mode 0x03, ADV_IND and ADV_RSP are not always aligned. # So, it seems that complete data can only be obtained once in a white. # Ex. The acquisition intervals was between 44 to 374 seconds. # It seems random... scanner.register_detection_callback(_wrapped_Linux(scanner)) else: # On Windows, data can be detected at intervals of 1 second or less. # And complete data will be obtained about every 1 second. scanner.register_detection_callback(_wrapped) await asyncio.sleep(scantime)
async def main(): queue = asyncio.Queue() def callback(device: BLEDevice, adv: AdvertisementData) -> None: # can use advertising data to filter here queue.put_nowait(device) async with BleakScanner(detection_callback=callback): # get the first matching device device = await queue.get() async with BleakClient(device) as client: # BlueZ doesn't have a proper way to get the MTU, so we have this hack. # If this doesn't work for you, you can set the client._mtu_size attribute # to override the value instead. if client.__class__.__name__ == "BleakClientBlueZDBus": await client._acquire_mtu() print("MTU:", client.mtu_size) # Write without response is limited to MTU - 3 bytes data = bytes(1000) # replace with real data chunk_size = client.mtu_size - 3 for chunk in (data[i:i + chunk_size] for i in range(0, len(data), chunk_size)): await client.write_gatt_char(CHAR_UUID, chunk)
async def run(): # Scan for TotTag devices for 5 seconds scanner = BleakScanner() await scanner.start() await asyncio.sleep(5.0) await scanner.stop() # Iterate through all discovered TotTag devices for device in await scanner.get_discovered_devices(): if device.name == 'TotTag': # Connect to the specified TotTag and locate the timestamp service print('Found Device: {}'.format(device.address)) try: async with BleakClient(device, use_cached=False) as client: for service in await client.get_services(): for characteristic in service.characteristics: if characteristic.uuid == TIMESTAMP_SERVICE_UUID: # Read and parse the current timestamp try: ts = bytes( await client.read_gatt_char(characteristic)) print('\tTimestamp: {}'.format( struct.unpack('<I', ts)[0])) except Exception as e: print( 'ERROR: Unable to read timestamp from TotTag!' ) except Exception as e: print('ERROR: Unable to connect to TotTag {}'.format( device.address))
async def run(): global deviceFound global deviceAddress global deviceConnected global fw_number scanner = BleakScanner() scanner.register_detection_callback(simple_callback) while True: await scanner.start() await asyncio.sleep(5.0) await scanner.stop() if deviceFound: deviceFound = False break async with BleakClient(deviceAddress) as client: deviceConnected = True svcs = await client.get_services() print("Services:") for service in svcs: print(service) fw_number = await client.read_gatt_char(OPENWIND_FW_CHARACTERISTIC_UUID ) print("Model Number: {0}".format("".join(map(chr, fw_number)))) sn_number = await client.read_gatt_char(OPENWIND_SN_CHARACTERISTIC_UUID ) if float(fw_number) >= 1.27: print("Model Number: {0}".format(sn_number.hex())) else: print("Model Number: {0}".format("".join(map(chr, sn_number)))) client.set_disconnected_callback(OW_DISCONNECT_CALLBACK) write_value = bytearray([0x2C]) await client.write_gatt_char(OPENWIND_MOV_ENABLE_CHARACTERISTIC_UUID, write_value) await asyncio.sleep(1.0) await client.start_notify(OPENWIND_WIND_CHARACTERISTIC_UUID, WIND_DATA_CALLBACK) while await client.is_connected(): await asyncio.sleep(5.0)
async def ble_device_scanner( scan_time=3.0, min_devices=1, scan_timeout=30.0, filters=None, silent=False, verbose=False, ): """ Performs a Bluetooth scan for available peripheral devices which advertise themselves as PFx Bricks. This coroutine will search for the required number of devices in scan_time chunks up until the scan_timeout interval has elapsed. :param scan_time: :obj:`float` scan time interval to look for devices :param min_devices: :obj:`int` minimum number of devices to look for before returning :param scan_timeout: :obj:`float` timeout interval for finding the required min_devices :param filters: :obj:`list` or `str` optional device name filters, e.g. "16 MB" :param silent: :obj:`boolean` a flag to disable printing of status :param verbose: :obj:`boolean` a flag to print a verbose list of advertising devices :returns: [:obj:`BLEDevice`] a list of PFx Brick device objects described in a Bleak BLEDevice class. """ def _filter_device(dc): if filters is not None: for f in filters: if f in dc.name: return True return False return True pfxdevs = [] total_scan_time = 0 if filters is not None: if isinstance(filters, str): filters = [filters] while len(pfxdevs) < min_devices: if not silent: print("Scanning...") async with BleakScanner() as scanner: await asyncio.sleep(scan_time) total_scan_time += scan_time devices = scanner.discovered_devices if not silent and len(devices) > 0: print("Found %d advertising devices" % (len(devices))) if verbose: for i, d in enumerate(devices): s = '%2d. UUID=%-36s "%s"' % (i + 1, d.address, d.name) print(s) for d in devices: if "PFx Brick" in d.name: if _filter_device(d): if not silent: print("Found %s UUID=%-36s" % (d.name, d.address)) pfxdevs.append(d) if total_scan_time > scan_timeout: break return pfxdevs
async def run(): async with BleakScanner() as scanner: await asyncio.sleep(5.0) devices = await scanner.get_discovered_devices() for d in devices: if ((d.name).upper() != ("UNKNOWN")): print("Name: ", (d.name)) print("Address: ", d.address) print("UUIDS: ", d.metadata['uuids'])
async def run(): scanner = BleakScanner() await scanner.start() await asyncio.sleep(2.0) await scanner.stop() rv = {} for each in scanner.discovered_devices: rv[each.address.lower()] = each.rssi, each.name return rv
async def uart_terminal(): """This is a simple "terminal" program that uses the Nordic Semiconductor (nRF) UART service. It reads from stdin and sends each line of data to the remote device. Any data received from the device is printed to stdout. """ queue = asyncio.Queue() def find_uart_device(device: BLEDevice, adv: AdvertisementData): # This assumes that the device includes the UART service UUID in the # advertising data. This test may need to be adjusted depending on the # actual advertising data supplied by the device. if UART_SERVICE_UUID.lower() in adv.service_uuids: queue.put_nowait(device) async with BleakScanner(detection_callback=find_uart_device): print("Scanning for a device...") # this just gets the first device that was queued, then we stop scanning device: BLEDevice = await queue.get() def handle_disconnect(_: BleakClient): print("Device was disconnected, goodbye.") # cancelling all tasks effectively ends the program for task in asyncio.all_tasks(): task.cancel() def handle_rx(_: int, data: bytearray): print("received:", data) async with BleakClient(device, disconnected_callback=handle_disconnect) as client: await client.start_notify(UART_TX_CHAR_UUID, handle_rx) loop = asyncio.get_event_loop() reader = asyncio.StreamReader() protocol = asyncio.StreamReaderProtocol(reader) await loop.connect_read_pipe(lambda: protocol, sys.stdin) print("Connected, start typing and press ENTER...") while True: # This waits until you type a line and press ENTER. # A real terminal program might put stdin in raw mode so that things # like CTRL+C get passed to the remote device. data = await reader.read(UART_SAFE_SIZE) # data will be empty on EOF (e.g. CTRL+D on *nix) if not data: break # some devices, like devices running MicroPython, expect Windows # line endings (uncomment line below if needed) # data = data.replace(b"\n", b"\r\n") await client.write_gatt_char(UART_RX_CHAR_UUID, data) print("sent:", data)
async def _scan_for_interval(self, interval: float) -> Iterable[ScanEntry]: """Scan advertisements for the given interval and return ScanEntry objects for all advertisements heard. """ if not self._scanner: self._scanner = BleakScanner(loop=self._bleak_loop) await self._scanner.start() await asyncio.sleep(interval) await self._scanner.stop() return await self._scanner.get_discovered_devices()