Skip to content

Commit 57a68f9

Browse files
committed
Add passive_scan.py example
1 parent 35a0784 commit 57a68f9

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

examples/passive_scan.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""
2+
Scanner using passive scanning mode
3+
--------------
4+
5+
Example similar to detection_callback.py, but using passive scanning mode and showing how to iterate devices
6+
7+
Updated on 2022-11-24 by bojanpotocnik <[email protected]>
8+
9+
"""
10+
import argparse
11+
import asyncio
12+
import logging
13+
from typing import Optional, List, Dict, Any, AsyncIterator, Tuple, Iterable
14+
15+
import bleak
16+
from bleak import BleakScanner, BLEDevice, AdvertisementData
17+
18+
logger = logging.getLogger(__name__)
19+
20+
21+
def _get_os_specific_scanning_params(
22+
uuids: Optional[List[str]], rssi: Optional[int], macos_use_bdaddr: bool = False
23+
) -> Dict[str, Any]:
24+
def get_bluez_dbus_scanning_params() -> Dict[str, Any]:
25+
from bleak.assigned_numbers import AdvertisementDataType
26+
from bleak.backends.bluezdbus.advertisement_monitor import OrPattern
27+
from bleak.backends.bluezdbus.scanner import (
28+
BlueZScannerArgs,
29+
BlueZDiscoveryFilters,
30+
)
31+
32+
filters = BlueZDiscoveryFilters(
33+
# UUIDs= Added below, because it cannot be None
34+
# RSSI= Added below, because it cannot be None
35+
Transport="le",
36+
DuplicateData=True,
37+
)
38+
if uuids:
39+
filters["UUIDs"] = uuids
40+
if rssi:
41+
filters["RSSI"] = rssi
42+
43+
# or_patterns ar required for BlueZ passive scanning
44+
or_patterns = [
45+
# General Discoverable (peripherals)
46+
OrPattern(0, AdvertisementDataType.FLAGS, b"\x02"),
47+
# BR/EDR Not Supported (BLE peripherals)
48+
OrPattern(0, AdvertisementDataType.FLAGS, b"\x04"),
49+
# General Discoverable, BR/EDR Not Supported (BLE peripherals)
50+
OrPattern(0, AdvertisementDataType.FLAGS, b"\x06"),
51+
# General Discoverable, LE and BR/EDR Capable (Controller), LE and BR/EDR Capable (Host) (computers, phones)
52+
OrPattern(0, AdvertisementDataType.FLAGS, b"\x1A"),
53+
]
54+
55+
return {"bluez": BlueZScannerArgs(filters=filters, or_patterns=or_patterns)}
56+
57+
def get_core_bluetooth_scanning_params() -> Dict[str, Any]:
58+
from bleak.backends.corebluetooth.scanner import CBScannerArgs
59+
60+
return {"cb": CBScannerArgs(use_bdaddr=macos_use_bdaddr)}
61+
62+
return {
63+
"BleakScannerBlueZDBus": get_bluez_dbus_scanning_params,
64+
"BleakScannerCoreBluetooth": get_core_bluetooth_scanning_params,
65+
# "BleakScannerP4Android": get_p4android_scanning_params,
66+
# "BleakScannerWinRT": get_winrt_scanning_params,
67+
}.get(bleak.get_platform_scanner_backend_type().__name__, lambda: {})()
68+
69+
70+
async def scan(
71+
uuids: Optional[Iterable[str]] = None,
72+
rssi: Optional[int] = None,
73+
macos_use_bdaddr: bool = False,
74+
) -> AsyncIterator[Tuple[BLEDevice, AdvertisementData]]:
75+
devices = asyncio.Queue()
76+
77+
def scan_callback(bd: BLEDevice, ad: AdvertisementData):
78+
devices.put_nowait((bd, ad))
79+
80+
async with BleakScanner(
81+
detection_callback=scan_callback,
82+
**_get_os_specific_scanning_params(uuids=uuids, rssi=rssi),
83+
scanning_mode="passive"
84+
):
85+
while True:
86+
try:
87+
yield await devices.get()
88+
except GeneratorExit:
89+
break
90+
91+
92+
async def main():
93+
parser = argparse.ArgumentParser()
94+
95+
parser.add_argument(
96+
"--services",
97+
metavar="<uuid>",
98+
nargs="*",
99+
help="UUIDs of one or more services to filter for",
100+
)
101+
102+
args = parser.parse_args()
103+
104+
async for device, adv_data in scan(
105+
uuids=args.services
106+
): # type: BLEDevice, AdvertisementData
107+
logger.info("%s: %r", device.address, adv_data)
108+
109+
110+
if __name__ == "__main__":
111+
logging.basicConfig(
112+
level=logging.INFO,
113+
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
114+
)
115+
116+
try:
117+
asyncio.run(main())
118+
except KeyboardInterrupt:
119+
pass

0 commit comments

Comments
 (0)