55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
"""Diagnostic BLE scan: list nearby devices and flag likely Shining Masks.
|
|
|
|
No connection is made -- this only listens for advertisements, so it is safe to
|
|
run any time::
|
|
|
|
python examples/scan.py
|
|
"""
|
|
|
|
import asyncio
|
|
|
|
from bleak import BleakScanner
|
|
|
|
import constants as C
|
|
|
|
|
|
async def main(timeout: float = 12.0):
|
|
print(f"Scanning {timeout:.0f}s for BLE devices "
|
|
f"(looking for name '{C.DEVICE_NAME_PREFIX}*' or service {C.SERVICE_UUID})...\n")
|
|
found = await BleakScanner.discover(timeout=timeout, return_adv=True)
|
|
|
|
rows = []
|
|
masks = []
|
|
for address, (dev, adv) in found.items():
|
|
name = adv.local_name or dev.name or "(no name)"
|
|
svcs = [s.lower() for s in (adv.service_uuids or [])]
|
|
is_mask = (
|
|
str(name).upper().startswith(C.DEVICE_NAME_PREFIX)
|
|
or C.SERVICE_UUID.lower() in svcs
|
|
or any("fff0" in s for s in svcs)
|
|
)
|
|
rows.append((adv.rssi if adv.rssi is not None else -999, dev.address, name, svcs, is_mask))
|
|
if is_mask:
|
|
masks.append((dev.address, name))
|
|
|
|
for rssi, address, name, svcs, is_mask in sorted(rows, reverse=True):
|
|
flag = " <== LIKELY MASK" if is_mask else ""
|
|
print(f" {address} rssi={rssi:>4} name={name!r} services={svcs}{flag}")
|
|
|
|
print()
|
|
if masks:
|
|
print("Likely mask(s) found:")
|
|
for address, name in masks:
|
|
print(f" address={address} name={name!r}")
|
|
print("\nConnect with, e.g.:")
|
|
print(f" python cli.py --address {masks[0][0]} light 80")
|
|
else:
|
|
print("No mask detected. Checklist:")
|
|
print(" * Power the mask on (and take it out of the phone app / disconnect the app).")
|
|
print(" * REMOVE it from the OS Bluetooth settings if you tried to 'pair' it there.")
|
|
print(" * Make sure Bluetooth is on and no other process holds the adapter.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|