예제 #1
1
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))
예제 #2
0
async def run():
    scanner = BleakScanner()
    scanner.register_detection_callback(detection_callback)
    while True:
        await scanner.start()
        await asyncio.sleep(0.5)
        await scanner.stop()
예제 #3
0
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)
예제 #4
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)
예제 #5
0
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()
예제 #7
0
    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
예제 #8
0
async def main():
    scanner = BleakScanner()
    scanner.register_detection_callback(simple_callback)

    while True:
        await scanner.start()
        await asyncio.sleep(5.0)
        await scanner.stop()
예제 #9
0
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()
예제 #10
0
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
예제 #11
0
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()
예제 #13
0
파일: scanner.py 프로젝트: irremotus/govee
    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()
예제 #14
0
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)
예제 #15
0
    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')
예제 #16
0
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))
예제 #17
0
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')
예제 #18
0
 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 []
예제 #19
0
파일: ble.py 프로젝트: Novakasa/pybricksdev
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)
예제 #20
0
    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
예제 #21
0
    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 = []
예제 #22
0
        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)
예제 #23
0
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))
예제 #25
0
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)
예제 #26
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
예제 #27
0
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'])
예제 #28
0
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
예제 #29
0
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)
예제 #30
0
    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()