bluetoothbluetooth-lowenergypython-bleak

Bluetooth Low Energy filter devices based on services


I am a beginner with BLE/Bluetooth. I am trying to communicate with a BLE enabled device, which is using a CH9141K BLE-to-serial bridge. I've got my host application successfully talking to the device using the bleak library for python.

So far I contacted the device directly by connecting through MAC or local name (or uuid on MacOS), which is working fine.

I now want to scan for devices, since it is quite likely that a user doesn't know the MAC or the local name for the device. (MacOS hides the MAC, and the local name can be changed.)

python3 discover.py (example from the bleak package) reports this:

AdvertisementData(local_name='device ', manufacturer_data={51212: b'1\x00\x00\x00\x00\x00'}, tx_power=0, rssi=-53)

I am a bit confused, doesn't a BLE device have to advertise the services it provides? I compared this to an example from the MicroPython aioble library (temp_sensor.py), which returns service_uuids for the services it provides.

My plan was to discover CH9141K devices first as efficiently as possible, then listen to each if they return a data packet valid for the device I'm looking for.

If I use service_explorer.py (again, from the bleak examples) I get:

2024-08-21 17:31:21,970 __main__ INFO: connecting to device...
2024-08-21 17:31:23,641 __main__ INFO: connected
2024-08-21 17:31:23,641 __main__ INFO: [Service] 0000180a-0000-1000-8000-00805f9b34fb (Handle: 14): Device Information
2024-08-21 17:31:23,686 __main__ INFO:   [Characteristic] 00002a23-0000-1000-8000-00805f9b34fb (Handle: 15): System ID (read), Value: bytearray(b'\x13\xdey\x00\x00\x10S\\')
2024-08-21 17:31:23,716 __main__ INFO:   [Characteristic] 00002a24-0000-1000-8000-00805f9b34fb (Handle: 17): Model Number String (read), Value: bytearray(b'CH9141')
2024-08-21 17:31:23,746 __main__ INFO:   [Characteristic] 00002a25-0000-1000-8000-00805f9b34fb (Handle: 19): Serial Number String (read), Value: bytearray(b'190420000000')
2024-08-21 17:31:23,791 __main__ INFO:   [Characteristic] 00002a26-0000-1000-8000-00805f9b34fb (Handle: 21): Firmware Revision String (read), Value: bytearray(b'VER1.0')
2024-08-21 17:31:23,821 __main__ INFO:   [Characteristic] 00002a27-0000-1000-8000-00805f9b34fb (Handle: 23): Hardware Revision String (read), Value: bytearray(b'VER1.0')
2024-08-21 17:31:23,851 __main__ INFO:   [Characteristic] 00002a28-0000-1000-8000-00805f9b34fb (Handle: 25): Software Revision String (read), Value: bytearray(b'VER1.0')
2024-08-21 17:31:23,895 __main__ INFO:   [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb (Handle: 27): Manufacturer Name String (read), Value: bytearray(b'WCH')
2024-08-21 17:31:23,925 __main__ INFO:   [Characteristic] 00002a50-0000-1000-8000-00805f9b34fb (Handle: 29): PnP ID (read), Value: bytearray(b'\x019\x07\x00\x00\x10\x01')
2024-08-21 17:31:23,938 __main__ INFO: [Service] 0000fff0-0000-1000-8000-00805f9b34fb (Handle: 31): Vendor specific
2024-08-21 17:31:24,001 __main__ INFO:   [Characteristic] 0000fff1-0000-1000-8000-00805f9b34fb (Handle: 32): Vendor specific (read,notify), Value: bytearray(b'')
2024-08-21 17:31:24,031 __main__ INFO:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 34): Client Characteristic Configuration, Value: bytearray(b'')
2024-08-21 17:31:24,061 __main__ INFO:     [Descriptor] 00002901-0000-1000-8000-00805f9b34fb (Handle: 35): Characteristic User Description, Value: bytearray(b'UART DATA')
2024-08-21 17:31:24,061 __main__ INFO:   [Characteristic] 0000fff2-0000-1000-8000-00805f9b34fb (Handle: 36): Vendor specific (write-without-response,write), Max write w/o rsp size: 197
2024-08-21 17:31:24,121 __main__ INFO:     [Descriptor] 00002901-0000-1000-8000-00805f9b34fb (Handle: 38): Characteristic User Description, Value: bytearray(b'BLE DATA')
2024-08-21 17:31:24,151 __main__ INFO:   [Characteristic] 0000fff3-0000-1000-8000-00805f9b34fb (Handle: 39): Vendor specific (read,write,notify), Value: bytearray(b'')
2024-08-21 17:31:24,181 __main__ INFO:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 41): Client Characteristic Configuration, Value: bytearray(b'')
2024-08-21 17:31:24,211 __main__ INFO:     [Descriptor] 00002901-0000-1000-8000-00805f9b34fb (Handle: 42): Characteristic User Description, Value: bytearray(b'BLE CONFIG')
2024-08-21 17:31:24,211 __main__ INFO: [Service] 0000ffe0-0000-1000-8000-00805f9b34fb (Handle: 43): Vendor specific
2024-08-21 17:31:24,211 __main__ INFO:   [Characteristic] 0000ffe1-0000-1000-8000-00805f9b34fb (Handle: 44): Vendor specific (notify)
2024-08-21 17:31:24,241 __main__ INFO:     [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 46): Client Characteristic Configuration, Value: bytearray(b'')
2024-08-21 17:31:24,271 __main__ INFO:     [Descriptor] 00002901-0000-1000-8000-00805f9b34fb (Handle: 47): Characteristic User Description, Value: bytearray(b'UART DATA')
2024-08-21 17:31:24,271 __main__ INFO:   [Characteristic] 0000ffe2-0000-1000-8000-00805f9b34fb (Handle: 48): Vendor specific (write-without-response,write), Max write w/o rsp size: 197
2024-08-21 17:31:24,301 __main__ INFO:     [Descriptor] 00002901-0000-1000-8000-00805f9b34fb (Handle: 50): Characteristic User Description, Value: bytearray(b'BLE DATA')
2024-08-21 17:31:24,301 __main__ INFO: disconnecting...
2024-08-21 17:31:24,303 __main__ INFO: disconnected

...though this connects to the device to iterate over services.

So the question is, how do I efficiently filter for devices providing specific services, or is it acceptable to connect to all discovered devices for a quick peek? Or is there an option I'm missing in BLE/Bleak? I need to know at a minimum that I'm dealing with a CH9141 device, it would probably better to look that it provides service 0xFFF0 as well. Both of these are easy to find after connecting.


Solution

  • This device just advertises DIS, which almost every device advertises, and it breaks the spec by using unassigned 16-bit service IDs. They picked 0xFFF0 and 0xFFE0 and I guess just hope they won't collide with anyone… That's not very robust, though if they have the very short range you're describing, I'm sure they get away with it almost all the time, which is why they did this rather than pay the fees required to get their own identifiers. But this is not particularly identifying of the device. Hopefully there's something more (maybe something in the device information service) that will really identify that this is the right device. "Is squatting on two easily-picked service identifiers" is not a great way to be sure.

    Typically when searching for a device like this you would look at its advertising to see if it's possibly the device you want and then connect to verify those devices that are possible. Once you've connected, the CBPeripheral ID will be pretty stable (I've seen them change, but it's rare), so you'll be able to use that in the future.

    This kind of heuristic, multi-step approach is very common. I've done it even when I controlled the device firmware and could put anything I wanted in the advertising packet.