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

Scanning BLE devices returns empty uuids in metadata (?) #437

Closed
rdagher opened this issue Feb 2, 2021 · 2 comments · Fixed by #534
Closed

Scanning BLE devices returns empty uuids in metadata (?) #437

rdagher opened this issue Feb 2, 2021 · 2 comments · Fixed by #534
Labels
Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend

Comments

@rdagher
Copy link

rdagher commented Feb 2, 2021

  • bleak version: 0.10.0
  • Python version: Python 3.8.5
  • Operating System: MacOS Catalina 10.15.7
  • BlueZ version (bluetoothctl -v) in case of Linux: N/A

Description

Hi,

I wanted to test scanning devices and print the details of the scanned device (name, metadata, etc.).

The devices are detected (name, address), nevertheless the metadata field metadata = {'uuids': [], ...} does not contain the service uuids which is expected to be a list of one element, in my case 'uuids': ['680c21d9-c946-4c1f-9c11-baa1c21329e7'].

The reason is I want to filter the scan output, application-side, on the device's service uuid to only report devices of interest.

For the test, I have two BLE devices running (namely DWDBB5 and DWD48C) - scan using a mobile app on Android (nrfConnect):
nrf-scan-screenshot

What I Did

Attached the test script containing two simple scanning functions.
ble_scan.py.txt
ble_scan_log.txt

Here's a snippet of what I get as output:

import asyncio
from bleak import BleakScanner
from bleak.backends.device import BLEDevice

from ppretty import ppretty



def dev_dump(dev:BLEDevice):
    #print(ppretty(dev, show_protected=True, show_static=True, show_properties=True))
    print(f'device {dev}:')
    print(f'\taddr = {dev.address}')
    print(f'\tname = {dev.name}')
    print(f'\trssi = {dev.rssi}')
    print(f'\tdetails = {dev.details}')
    print(f'\tmetadata = {dev.metadata}')

    print(f'>> Services (Mac) = {dev.details.services}')
    print(ppretty(dev.details.services, show_protected=True, show_static=True, show_properties=True))

async def basic_scan():
    devices = await BleakScanner.discover()
    for d in devices:
        dev_dump(d)


async def adv_scan(scan_duration:int, service_uuid:str):
    # scan for devices
    scanner = BleakScanner(filters={"UUIDs":[service_uuid], "DuplicateData":False})
    def detection_callback(device, advertisement_data):
        print("detected:", device, " – RSSI:", device.rssi, " – adv data: ", advertisement_data)

    scanner.register_detection_callback(detection_callback)
    await scanner.start()
    await asyncio.sleep(scan_duration)
    await scanner.stop()
    scanned_devices = await scanner.get_discovered_devices()
    print(f'Device discovery filtered output:')
    for d in scanned_devices:
        dev_dump(d)




loop = asyncio.get_event_loop()

print('Basic Scan:')
loop.run_until_complete(basic_scan())
loop.run_until_complete(basic_scan())


DWM_SERVICE_UUID = '680c21d9-c946-4c1f-9c11-baa1c21329e7'
print(f'Filtering scan on service: {DWM_SERVICE_UUID}')
loop.run_until_complete(adv_scan(scan_duration=6, service_uuid=DWM_SERVICE_UUID))
$ python ble_scan.py 
Basic Scan:
device 7C8844F3-6F25-40FF-BAB6-532F089721ED: Apple, Inc. (b'\t\x06\x03\n\xc0\xa8\x01\n'):
	addr = 7C8844F3-6F25-40FF-BAB6-532F089721ED
	name = Unknown
	rssi = 0
	details = <CBPeripheral: 0x7f988c0a2e10, identifier = 7C8844F3-6F25-40FF-BAB6-532F089721ED, name = (null), state = disconnected>
	metadata = {'uuids': [], 'manufacturer_data': {76: b'\t\x06\x03\n\xc0\xa8\x01\n'}, 'delegate': <CentralManagerDelegate: 0x7f988af235d0>}
>> Services (Mac) = <native-selector services of <CBPeripheral: 0x7f988c0a2e10, identifier = 7C8844F3-6F25-40FF-BAB6-532F089721ED, name = (null), state = disconnected>>
native_selector(
    definingClass = <class 'objc.CBPeripheral'>, 
    isClassMethod = False, 
    ..., 
    self = objc.NSKVONotifying_CBPeripheral(), 
    signature = bytes()
)
Filtering scan on service: 680c21d9-c946-4c1f-9c11-baa1c21329e7
detected: 52AE0205-7F1E-4597-869C-CBB46747834B: DWD48C  – RSSI: -58  – adv data:  AdvertisementData(local_name='DWD48C')
detected: 6CC6A737-C441-4BB3-BF09-2F48E19FA89F: Unknown  – RSSI: -91  – adv data:  AdvertisementData(manufacturer_data={2305: b'q\x108\xef`\n?x\xf2p\xd9tR'}, service_uuids=['0000febe-0000-1000-8000-00805f9b34fb', '0000fe26-0000-1000-8000-00805f9b34fb'])
detected: 6CFADC06-2C11-4884-9F4F-FA3CBAA4D672: DWDBB5  – RSSI: -66  – adv data:  AdvertisementData(local_name='DWDBB5')
Device discovery filtered output:
device 52AE0205-7F1E-4597-869C-CBB46747834B: DWD48C:
	addr = 52AE0205-7F1E-4597-869C-CBB46747834B
	name = DWD48C
	rssi = 0
	details = <CBPeripheral: 0x7f988c071570, identifier = 52AE0205-7F1E-4597-869C-CBB46747834B, name = DWD48C, state = disconnected>
	metadata = {'uuids': [], 'manufacturer_data': {}, 'delegate': <CentralManagerDelegate: 0x7f988ac4e250>}
>> Services (Mac) = <native-selector services of <CBPeripheral: 0x7f988c071570, identifier = 52AE0205-7F1E-4597-869C-CBB46747834B, name = DWD48C, state = disconnected>>
native_selector(
    definingClass = <class 'objc.CBPeripheral'>, 
    isClassMethod = False, 
    ..., 
    self = objc.NSKVONotifying_CBPeripheral(), 
    signature = bytes()
)
device 6CC6A737-C441-4BB3-BF09-2F48E19FA89F: This value has special meaning depending on the context in which it used. Link Manager Protocol (LMP): This value may be used in the internal and interoperability tests before a Company ID has been assigned. This value shall not be used in shipping end products. Device ID Profile: This value is reserved as the default vendor ID when no Device ID service record is present in a remote device. (b'q\x108\xef`\n?x\xf2p\xd9tR'):
	addr = 6CC6A737-C441-4BB3-BF09-2F48E19FA89F
	name = Unknown
	rssi = 0
	details = <CBPeripheral: 0x7f988ac24310, identifier = 6CC6A737-C441-4BB3-BF09-2F48E19FA89F, name = (null), state = disconnected>
	metadata = {'uuids': ['0000febe-0000-1000-8000-00805f9b34fb', '0000fe26-0000-1000-8000-00805f9b34fb'], 'manufacturer_data': {2305: b'q\x108\xef`\n?x\xf2p\xd9tR'}, 'delegate': <CentralManagerDelegate: 0x7f988ac4e250>}
>> Services (Mac) = <native-selector services of <CBPeripheral: 0x7f988ac24310, identifier = 6CC6A737-C441-4BB3-BF09-2F48E19FA89F, name = (null), state = disconnected>>
native_selector(
    definingClass = <class 'objc.CBPeripheral'>, 
    isClassMethod = False, 
    ..., 
    self = objc.NSKVONotifying_CBPeripheral(), 
    signature = bytes()
)
device 6CFADC06-2C11-4884-9F4F-FA3CBAA4D672: DWDBB5:
	addr = 6CFADC06-2C11-4884-9F4F-FA3CBAA4D672
	name = DWDBB5
	rssi = 0
	details = <CBPeripheral: 0x7f988de0edb0, identifier = 6CFADC06-2C11-4884-9F4F-FA3CBAA4D672, name = DWDBB5, state = disconnected>
	metadata = {'uuids': [], 'manufacturer_data': {}, 'delegate': <CentralManagerDelegate: 0x7f988ac4e250>}
>> Services (Mac) = <native-selector services of <CBPeripheral: 0x7f988de0edb0, identifier = 6CFADC06-2C11-4884-9F4F-FA3CBAA4D672, name = DWDBB5, state = disconnected>>
native_selector(
    definingClass = <class 'objc.CBPeripheral'>, 
    isClassMethod = False, 
    ..., 
    self = objc.NSKVONotifying_CBPeripheral(), 
    signature = bytes()
)

Thanks in advance for your help, and I hope I did not misinterpret the semantics of the uuids field. I was counting on this field from the scan results for a simple filtering.

P.S I am aware of the fact that filtering is not yet provided on Mac and of issue #230.

P.S Suspecting relation to issue #329.

P.S For now, I have currently a terribly slow and ugly workaround that uses service discovery on the scanned device, which becomes terribly slow when many BLE devices are around and especially some of them refusing/stalling (for a reason) to respond to service discovery.

Regards,
Roudy

@dlech
Copy link
Collaborator

dlech commented Feb 2, 2021

Yes, there is some work to be done to bring metadata up to date with the new register_detection_callback() and make it work in a more consistent way cross-platform (very briefly discussed in #334).

For now you can probably work around it by collecting the needed information yourself in the callback instead of using the metadata attribute.

@dlech dlech added the Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend label Feb 2, 2021
@dlech dlech linked a pull request May 12, 2021 that will close this issue
dlech added a commit that referenced this issue May 13, 2021
Fix missing delegate in BLEDevice metadata

Fixes #448
Fixes #437
@huseyinege
Copy link

I have checked the bleak/backends/corebluetooth/scanner.py and it is the updated version. However i have the same problem. This is my piece of code:
async def run():
scanner = BleakScanner()
scanner.register_detection_callback(detection_callback)
await scanner.start()
await asyncio.sleep(20.0)
await scanner.stop()
scanned_devices= await scanner.get_discovered_devices()
for d in scanned_devices:
if d.address in Dict:
print(d)
print(d.metadata.values())

And this is the output i get:
E3:EB:F8:F2:9E:9D: Nordic_UART
dict_values([[], {89: b''}])
CA:56:C9:07:54:CF: Nordic_UART
dict_values([[], {89: b''}])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants