Skip to content

Commit a818521

Browse files
committed
backends/scanner: always filter by service_uuids
It was noted that on Linux, if another app was scanning at the same time, BlueZ would trigger RSSI changes for all devices, even if they they didn't match the service_uuids filter. This change ensures that we always filter by service_uuids, even if the OS isn't doing it for us. On Windows, the OS wasn't filtering for us anyway, so we can just move that code to the shared call_detection_callbacks() so that all backends will make use of it. Fixes: #1534
1 parent 37152ac commit a818521

File tree

3 files changed

+24
-14
lines changed

3 files changed

+24
-14
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Fixed
3434
* Fixed using wrong value for ``tx_power`` in Android backend. Fixes #1532.
3535
* Fixed 4-character UUIDs not working on ``BleakClient.*_gatt_char`` methods. Fixes #1498.
3636
* Fixed race condition with getting max PDU size on Windows. Fixes #1497.
37+
* Fixed filtering advertisement data by service UUID when multiple apps are scanning. Fixes #1534.
3738

3839
`0.21.1`_ (2023-09-08)
3940
======================

bleak/backends/scanner.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,24 @@ def call_detection_callbacks(
206206
Backend implementations should call this method when an advertisement
207207
event is received from the OS.
208208
"""
209+
210+
# Backends will make best effort to filter out advertisements that
211+
# don't match the service UUIDs, but if other apps are scanning at the
212+
# same time or something like that, we may still receive advertisements
213+
# that don't match. So we need to do more filtering here to get the
214+
# expected behavior.
215+
216+
if self._service_uuids:
217+
if not advertisement_data.service_uuids:
218+
return
219+
220+
for uuid in advertisement_data.service_uuids:
221+
if uuid in self._service_uuids:
222+
break
223+
else:
224+
# if there were no matching service uuids, the don't call the callback
225+
return
226+
209227
for callback in self._ad_callbacks.values():
210228
callback(device, advertisement_data)
211229

bleak/backends/winrt/scanner.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ def __init__(
9696
else:
9797
self._scanning_mode = BluetoothLEScanningMode.ACTIVE
9898

99+
# Unfortunately, due to the way Windows handles filtering, we can't
100+
# make use of the service_uuids filter here. If we did we would only
101+
# get the advertisement data or the scan data, but not both, so would
102+
# miss out on other essential data. Advanced users can pass their own
103+
# filters though if they want to.
99104
self._signal_strength_filter = kwargs.get("SignalStrengthFilter", None)
100105
self._advertisement_filter = kwargs.get("AdvertisementFilter", None)
101106

@@ -198,20 +203,6 @@ def _received_handler(
198203
bdaddr, local_name, raw_data, advertisement_data
199204
)
200205

201-
# On Windows, we have to fake service UUID filtering. If we were to pass
202-
# a BluetoothLEAdvertisementFilter to the BluetoothLEAdvertisementWatcher
203-
# with the service UUIDs appropriately set, we would no longer receive
204-
# scan response data (which commonly contains the local device name).
205-
# So we have to do it like this instead.
206-
207-
if self._service_uuids:
208-
for uuid in uuids:
209-
if uuid in self._service_uuids:
210-
break
211-
else:
212-
# if there were no matching service uuids, the don't call the callback
213-
return
214-
215206
self.call_detection_callbacks(device, advertisement_data)
216207

217208
def _stopped_handler(self, sender, e):

0 commit comments

Comments
 (0)