Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discovery filter #565

Merged
merged 9 commits into from
Jun 7, 2021
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Added
* add mtu_size property for clients
* WinRT backend added
* Added ``BleakScanner.discovered_devices`` property.
* Added ``BleakScanner.find_device_by_filter`` static method.
* Added ``scanner_byname.py`` example.
* Added optional command line argument to specify device to all applicable examples.

Changed
~~~~~~~
Expand Down
38 changes: 32 additions & 6 deletions bleak/backends/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ def __repr__(self) -> str:
Optional[Awaitable[None]],
]

AdvertisementDataFilter = Callable[
[BLEDevice, AdvertisementData],
bool,
]


class BaseBleakScanner(abc.ABC):
"""Interface for Bleak Bluetooth LE Scanners"""
Expand Down Expand Up @@ -195,10 +200,33 @@ async def find_device_by_address(

"""
device_identifier = device_identifier.lower()
return await cls.find_device_by_filter(
lambda d, ad: d.address.lower() == device_identifier
)

@classmethod
async def find_device_by_filter(
cls, filterfunc: AdvertisementDataFilter, timeout: float = 10.0, **kwargs
) -> Optional[BLEDevice]:
"""A convenience method for obtaining a ``BLEDevice`` object specified by a filter function.

Args:
filterfunc (AdvertisementDataFilter): A function that is called for every BLEDevice found. It should return True only for the wanted device.
timeout (float): Optional timeout to wait for detection of specified peripheral before giving up. Defaults to 10.0 seconds.

Keyword Args:
adapter (str): Bluetooth adapter to use for discovery.

Returns:
The ``BLEDevice`` sought or ``None`` if not detected.

"""
stop_scanning_event = asyncio.Event()
found_device_queue = asyncio.Queue()

def stop_if_detected(d: BLEDevice, ad: AdvertisementData):
if d.address.lower() == device_identifier:
if filterfunc(d, ad):
found_device_queue.put_nowait(d)
stop_scanning_event.set()

async with cls(
Expand All @@ -208,8 +236,6 @@ def stop_if_detected(d: BLEDevice, ad: AdvertisementData):
await asyncio.wait_for(stop_scanning_event.wait(), timeout=timeout)
dlech marked this conversation as resolved.
Show resolved Hide resolved
except asyncio.TimeoutError:
return None
return next(
d
for d in scanner.discovered_devices
if d.address.lower() == device_identifier
)
if found_device_queue.empty():
return None
return found_device_queue.get_nowait()
3 changes: 3 additions & 0 deletions examples/async_callback_with_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
NOTIFICATION_UUID = f"0000{0xFFE1:x}-0000-1000-8000-00805f9b34fb"
if len(sys.argv) == 3:
ADDRESS = sys.argv[1]
NOTIFICATION_UUID = sys.argv[2]


async def run_ble_client(address: str, queue: asyncio.Queue):
Expand Down
17 changes: 11 additions & 6 deletions examples/connect_by_bledevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@

import asyncio
import platform
import sys

from bleak import BleakClient, BleakScanner
from bleak.exc import BleakError


ADDRESS = (
"24:71:89:cc:09:05"
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
if len(sys.argv) == 2:
ADDRESS = sys.argv[1]


async def print_services(ble_address: str):
device = await BleakScanner.find_device_by_address(ble_address, timeout=20.0)
if not device:
Expand All @@ -20,10 +30,5 @@ async def print_services(ble_address: str):
print(service)


ble_address = (
"24:71:89:cc:09:05"
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
loop = asyncio.get_event_loop()
loop.run_until_complete(print_services(ble_address))
loop.run_until_complete(print_services(ADDRESS))
16 changes: 10 additions & 6 deletions examples/enable_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

"""

import sys
import logging
import asyncio
import platform
Expand All @@ -18,6 +19,14 @@


CHARACTERISTIC_UUID = "f000aa65-0451-4000-b000-000000000000" # <--- Change to the characteristic you want to enable notifications from.
ADDRESS = (
"24:71:89:cc:09:05" # <--- Change to your device's address here if you are using Windows or Linux
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46" # <--- Change to your device's address here if you are using macOS
)
if len(sys.argv) == 3:
ADDRESS = sys.argv[1]
CHARACTERISTIC_UUID = sys.argv[2]


def notification_handler(sender, data):
Expand Down Expand Up @@ -48,11 +57,6 @@ async def run(address, debug=False):
import os

os.environ["PYTHONASYNCIODEBUG"] = str(1)
address = (
"24:71:89:cc:09:05" # <--- Change to your device's address here if you are using Windows or Linux
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46" # <--- Change to your device's address here if you are using macOS
)
loop = asyncio.get_event_loop()
# loop.set_debug(True)
loop.run_until_complete(run(address, True))
loop.run_until_complete(run(ADDRESS, True))
16 changes: 10 additions & 6 deletions examples/get_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@

"""

import sys
import asyncio
import platform

from bleak import BleakClient

ADDRESS = (
"24:71:89:cc:09:05"
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
if len(sys.argv) == 2:
ADDRESS = sys.argv[1]


async def print_services(mac_addr: str):
async with BleakClient(mac_addr) as client:
Expand All @@ -22,10 +31,5 @@ async def print_services(mac_addr: str):
print(service)


mac_addr = (
"24:71:89:cc:09:05"
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
loop = asyncio.get_event_loop()
loop.run_until_complete(print_services(mac_addr))
loop.run_until_complete(print_services(ADDRESS))
8 changes: 6 additions & 2 deletions examples/philips_hue.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@

"""

import sys
import asyncio
import logging

from bleak import BleakClient

ADDRESS = "EB:F0:49:21:95:4F"
if len(sys.argv) == 2:
ADDRESS = sys.argv[1]


LIGHT_CHARACTERISTIC = "932c32bd-0002-47a2-835a-a8d455b859dd"
BRIGHTNESS_CHARACTERISTIC = "932c32bd-0003-47a2-835a-a8d455b859dd"
Expand Down Expand Up @@ -106,7 +111,6 @@ async def run(address, debug=False):


if __name__ == "__main__":
address = "EB:F0:49:21:95:4F"
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_until_complete(run(address, True))
loop.run_until_complete(run(ADDRESS, True))
3 changes: 3 additions & 0 deletions examples/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import asyncio
import platform
import sys

from bleak import BleakScanner

Expand All @@ -19,6 +20,8 @@
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46" # <--- Change to your device's address here if you are using macOS
)
if len(sys.argv) == 2:
address = sys.argv[1]
jackjansen marked this conversation as resolved.
Show resolved Hide resolved


async def run():
Expand Down
32 changes: 32 additions & 0 deletions examples/scanner_byname.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Bleak Scanner
-------------



Updated on 2020-08-12 by hbldh <henrik.blidh@nedomkull.com>

"""

import asyncio
import platform
import sys

from bleak import BleakScanner


if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} name")
sys.exit(1)
wanted_name = sys.argv[1].lower()


async def run():
device = await BleakScanner.find_device_by_filter(
lambda d, ad: d.name and d.name.lower() == wanted_name
)
print(device)


loop = asyncio.get_event_loop()
loop.run_until_complete(run())
dlech marked this conversation as resolved.
Show resolved Hide resolved
17 changes: 11 additions & 6 deletions examples/service_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,22 @@
Created on 2019-03-25 by hbldh <henrik.blidh@nedomkull.com>

"""

import sys
import platform
import asyncio
import logging

from bleak import BleakClient

ADDRESS = (
"24:71:89:cc:09:05"
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
if len(sys.argv) == 2:
ADDRESS = sys.argv[1]


async def run(address, debug=False):
log = logging.getLogger(__name__)
Expand Down Expand Up @@ -59,11 +69,6 @@ async def run(address, debug=False):


if __name__ == "__main__":
address = (
"24:71:89:cc:09:05"
if platform.system() != "Darwin"
else "B9EA5233-37EF-4DD6-87A8-2A875E821C46"
)
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_until_complete(run(address, True))
loop.run_until_complete(run(ADDRESS, True))