1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
import asyncio
import contextlib
import sys
import pytest
from bumble import data_types
from bumble.core import UUID
from bumble.device import Device
from bleak import BleakScanner
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
from bleak.uuids import normalize_uuid_str
from tests.integration.conftest import configure_and_power_on_bumble_peripheral
DEFAULT_TIMEOUT = 5.0
async def test_discover(bumble_peripheral: Device):
"""Scanner discovery is finding the device."""
await configure_and_power_on_bumble_peripheral(bumble_peripheral)
devices = await BleakScanner.discover(return_adv=True)
filtered_devices = list(
filter(
lambda device: device[1].local_name == bumble_peripheral.name,
devices.values(),
)
)
assert len(filtered_devices) == 1
assert filtered_devices[0][1].local_name == bumble_peripheral.name
if sys.platform != "darwin":
# accessing the address is not possible on macOS
assert filtered_devices[0][0].address == str(bumble_peripheral.static_address)
@pytest.mark.parametrize("service_uuid_available", [True, False])
async def test_discover_filter_by_service_uuid(
bumble_peripheral: Device,
service_uuid_available: bool,
):
"""Scanner discovery is filtering service uuids correctly."""
await configure_and_power_on_bumble_peripheral(
bumble_peripheral,
additional_adv_data=(
[data_types.IncompleteListOf16BitServiceUUIDs([UUID(0x180F)])]
if service_uuid_available
else []
),
)
found_adv_data_future: asyncio.Future[AdvertisementData] = asyncio.Future()
def detection_callback(device: BLEDevice, adv_data: AdvertisementData):
if device.name == bumble_peripheral.name:
found_adv_data_future.set_result(adv_data)
async with BleakScanner(
detection_callback,
service_uuids=[normalize_uuid_str("180f")],
):
found_adv_data = None
with contextlib.suppress(asyncio.TimeoutError):
found_adv_data = await asyncio.wait_for(
found_adv_data_future, timeout=DEFAULT_TIMEOUT
)
if service_uuid_available:
assert found_adv_data is not None
else:
assert found_adv_data is None
async def test_adv_data_simple(bumble_peripheral: Device):
"""Simple advertising data is parsed correct."""
await configure_and_power_on_bumble_peripheral(bumble_peripheral)
found_adv_data_future: asyncio.Future[AdvertisementData] = asyncio.Future()
def detection_callback(device: BLEDevice, adv_data: AdvertisementData):
if device.name == bumble_peripheral.name:
found_adv_data_future.set_result(adv_data)
async with BleakScanner(detection_callback):
found_adv_data = await asyncio.wait_for(
found_adv_data_future, timeout=DEFAULT_TIMEOUT
)
assert found_adv_data is not None
assert found_adv_data.local_name == bumble_peripheral.name
assert found_adv_data.manufacturer_data == {}
assert found_adv_data.service_data == {}
assert found_adv_data.service_uuids == []
assert found_adv_data.tx_power is None
assert found_adv_data.platform_data
# Verify that this value is an integer and not some other
# type from a ffi binding framework.
assert isinstance(found_adv_data.rssi, int)
# The rssi can vary. So we only check for a plausible range.
assert -127 <= found_adv_data.rssi < 0
async def test_adv_data_complex(bumble_peripheral: Device):
"""Complex advertising data is parsed correct."""
await configure_and_power_on_bumble_peripheral(
bumble_peripheral,
[
data_types.ManufacturerSpecificData(0x1234, b"MFG"),
data_types.IncompleteListOf16BitServiceUUIDs([UUID(0x180F)]),
data_types.TxPowerLevel(123),
data_types.ServiceData16BitUUID(UUID(0x180F), b"SER"),
],
)
found_adv_data_future: asyncio.Future[AdvertisementData] = asyncio.Future()
def detection_callback(device: BLEDevice, adv_data: AdvertisementData):
if device.name == bumble_peripheral.name:
found_adv_data_future.set_result(adv_data)
async with BleakScanner(detection_callback):
found_adv_data = await asyncio.wait_for(
found_adv_data_future, timeout=DEFAULT_TIMEOUT
)
assert found_adv_data is not None
assert found_adv_data.local_name == bumble_peripheral.name
assert found_adv_data.manufacturer_data == {0x1234: b"MFG"}
assert found_adv_data.service_data == {
"0000180f-0000-1000-8000-00805f9b34fb": b"SER"
}
assert found_adv_data.service_uuids == ["0000180f-0000-1000-8000-00805f9b34fb"]
assert found_adv_data.tx_power == 123
assert found_adv_data.platform_data
# Verify that this value is an integer and not some other
# type from a ffi binding framework.
assert isinstance(found_adv_data.rssi, int)
# The rssi can vary. So we only check for a plausible range.
assert -127 <= found_adv_data.rssi < 0
|