diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aef37052..ecfd4b95 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,6 +34,7 @@ Fixed * Fixed using wrong value for ``tx_power`` in Android backend. Fixes #1532. * Fixed 4-character UUIDs not working on ``BleakClient.*_gatt_char`` methods. Fixes #1498. * Fixed race condition with getting max PDU size on Windows. Fixes #1497. +* Fixed filtering advertisement data by service UUID when multiple apps are scanning. Fixes #1534. `0.21.1`_ (2023-09-08) ====================== diff --git a/bleak/backends/scanner.py b/bleak/backends/scanner.py index f59557b9..693b20db 100644 --- a/bleak/backends/scanner.py +++ b/bleak/backends/scanner.py @@ -206,6 +206,24 @@ def call_detection_callbacks( Backend implementations should call this method when an advertisement event is received from the OS. """ + + # Backends will make best effort to filter out advertisements that + # don't match the service UUIDs, but if other apps are scanning at the + # same time or something like that, we may still receive advertisements + # that don't match. So we need to do more filtering here to get the + # expected behavior. + + if self._service_uuids: + if not advertisement_data.service_uuids: + return + + for uuid in advertisement_data.service_uuids: + if uuid in self._service_uuids: + break + else: + # if there were no matching service uuids, the don't call the callback + return + for callback in self._ad_callbacks.values(): callback(device, advertisement_data) diff --git a/bleak/backends/winrt/scanner.py b/bleak/backends/winrt/scanner.py index f250fa98..651fbc75 100644 --- a/bleak/backends/winrt/scanner.py +++ b/bleak/backends/winrt/scanner.py @@ -96,6 +96,11 @@ def __init__( else: self._scanning_mode = BluetoothLEScanningMode.ACTIVE + # Unfortunately, due to the way Windows handles filtering, we can't + # make use of the service_uuids filter here. If we did we would only + # get the advertisement data or the scan data, but not both, so would + # miss out on other essential data. Advanced users can pass their own + # filters though if they want to. self._signal_strength_filter = kwargs.get("SignalStrengthFilter", None) self._advertisement_filter = kwargs.get("AdvertisementFilter", None) @@ -198,20 +203,6 @@ def _received_handler( bdaddr, local_name, raw_data, advertisement_data ) - # On Windows, we have to fake service UUID filtering. If we were to pass - # a BluetoothLEAdvertisementFilter to the BluetoothLEAdvertisementWatcher - # with the service UUIDs appropriately set, we would no longer receive - # scan response data (which commonly contains the local device name). - # So we have to do it like this instead. - - if self._service_uuids: - for uuid in uuids: - if uuid in self._service_uuids: - break - else: - # if there were no matching service uuids, the don't call the callback - return - self.call_detection_callbacks(device, advertisement_data) def _stopped_handler(self, sender, e):