getsenic / gatt-python

Bluetooth GATT SDK for Python
MIT License
318 stars 86 forks source link

Passive scan feature #24

Open Snevzor opened 6 years ago

Snevzor commented 6 years ago

Hi!

I would need a passive scan function to get the RSSI values from advertisement data at a relative high rate (like hcitool lescan --passive). The discover function is way too slow for this.

Is this even supported by the dbus API? I don't know where to start.

Best regards

ukBaz commented 6 years ago

Hello,

You are correct that there is currently no support in the DBus API to select scanning in passive versus active mode.

Historically the issue with the DBus API has been that it did not support reporting duplicate advertisements from devices meaning that there was no updates when the RSSI changed. As of BlueZ 5.47 duplicates are now supported in the DBus API: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt?h=5.47#n107

Snevzor commented 6 years ago

Thanks for the fast and clear response!

So if I understand correct, with BlueZ 5.47 I can get updates when RSSI changes but it is still active scanning only?

In that case I might need to resort to gatt-python + something like aioblescan.

ukBaz commented 6 years ago

So if I understand correct, with BlueZ 5.47 I can get updates when RSSI changes but it is still active scanning only?

While I haven't tested it myself, that would be my expectation from following the conversation on the BlueZ mailing list.

In that case I might need to resort to gatt-python + something like aioblescan

I have found aioblescan very good for detecting beacons. The only downside is that it needs to run as root because it is using HCI/sockets.

Snevzor commented 6 years ago

Thanks @ukBaz! Unfortunately it seems that gatt-python requires devices to be 'discovered' first to be able to connect. They are not 'discovered' when scanned by hcitool or aioblescan. Maybe you've stumbled upon this as well?

ukBaz commented 6 years ago

I have not mixed and matched libraries so have not seen the problem directly. Given what I understand about the two libraries your findings do not surprise me.

This is getting to the edge of my knowledge so please treat the information below with some caution...

The BlueZ architecture is split between the Linux kernel and user space. The raw HCI socket connection used by aioblescan is controlling the Linux kernel directly The DBus API allows the user space (through bluetoothd) to control the kernel. bluetoothd adds a lot of flow control and status tracking to assist users. If devices are discovered with raw HCI socket commands then my assumption is that bluetoothd does not get updated to know about them

There is another BlueZ API called Bluetooth Management interface (mgmt) that operates in the user space but is more HCI socket like. It is not possible to access the mgmt API using Python. The problem seems to be that the current Python socket module doesn't let you get at it. The relevant code appears to be in makesockaddr() in CPython's socketmodule.c - see https://github.com/python/cpython/blob/master/Modules/socketmodule.c#L1276. It only ever seems to set the dev and bdaddr members, leaving the hci_channel field set to 0 (HCI_CHANNEL_RAW).

There is a presentation called "Bluetooth on modern Linux" that has more information about the BlueZ architecture: slides: https://elinux.org/images/8/89/Janc.pdf video: https://youtu.be/tclS9arLFzk

Snevzor commented 6 years ago

I've just read the presentation and tested with btmgt before reading your latest comment, so we are on the same track!

btmgt indeed seems to be more HCI socket like and the devices that get discovered using this tool can again not be accessed with bluetoothd unfortunatately. It's a pity that btmgmt cannot be accessed using Python, that would have been my next search.

I'm convinced in the whole bluetoothd + dbus story but I also really need to have passive scanning functionality. Currently we are using HCI stuff and that can really not be considered stable.

ukBaz commented 6 years ago

Maybe worth getting in contact with the developers of BlueZ directly to ask the question about how to solve the issue you are having with the DBus API? http://www.bluez.org/contact/

Snevzor commented 6 years ago

I've talked with the author of https://elinux.org/images/8/89/Janc.pdf at #bluez-users on freenode. He confirmed that indeed the current D-Bus API does not support passive scanning for discovery. Passive scanning is only used for connection creation. (Apparently even if this is added to BlueZ now, it appears that the kernel is not exposing this enough.)

Basically, it is unlikely that we'll see passive scanning in gatt-python any time soon.

JlnWntr commented 5 years ago

But is there any way to get RSSI-values from a connected device using gatt-python?