Passing a boolean `exclude_known_noisy_beacons` to `bluetooth` plugin.

The logic to exclude BLE beacons from randomized devices needs to be a
bit more granular and not limited only to the reported device
manufacturer.
This commit is contained in:
Fabio Manganiello 2023-03-22 15:29:19 +01:00
parent f6e09d34e4
commit 01d323fad0
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
3 changed files with 24 additions and 32 deletions

View File

@ -60,6 +60,7 @@ class BLEManager(BaseBluetoothManager):
device_queue=self._device_queue, device_queue=self._device_queue,
device_cache=self._device_cache, device_cache=self._device_cache,
entity_cache=self._cache, entity_cache=self._cache,
exclude_known_noisy_beacons=self._exclude_known_noisy_beacons,
) )
""" Bluetooth device event handler """ """ Bluetooth device event handler """
self._main_loop: Optional[asyncio.AbstractEventLoop] = None self._main_loop: Optional[asyncio.AbstractEventLoop] = None

View File

@ -28,6 +28,7 @@ class BaseBluetoothManager(ABC, threading.Thread):
device_queue: Queue[BluetoothDevice], device_queue: Queue[BluetoothDevice],
service_uuids: Optional[Collection[RawServiceClass]] = None, service_uuids: Optional[Collection[RawServiceClass]] = None,
device_cache: Optional[EntityCache] = None, device_cache: Optional[EntityCache] = None,
exclude_known_noisy_beacons: bool = True,
**kwargs, **kwargs,
): ):
""" """
@ -40,6 +41,7 @@ class BaseBluetoothManager(ABC, threading.Thread):
:param device_queue: Queue used by the ``EventHandler`` to publish :param device_queue: Queue used by the ``EventHandler`` to publish
updates with the new parsed device entities. updates with the new parsed device entities.
:param device_cache: Cache used to keep track of discovered devices. :param device_cache: Cache used to keep track of discovered devices.
:param exclude_known_noisy_beacons: Exclude known noisy beacons.
""" """
kwargs['name'] = f'Bluetooth:{self.__class__.__name__}' kwargs['name'] = f'Bluetooth:{self.__class__.__name__}'
super().__init__(**kwargs) super().__init__(**kwargs)
@ -53,6 +55,7 @@ class BaseBluetoothManager(ABC, threading.Thread):
self._scan_lock = scan_lock self._scan_lock = scan_lock
self._scan_enabled = scan_enabled self._scan_enabled = scan_enabled
self._device_queue = device_queue self._device_queue = device_queue
self._exclude_known_noisy_beacons = exclude_known_noisy_beacons
self._cache = device_cache or EntityCache() self._cache = device_cache or EntityCache()
""" Cache of discovered devices. """ """ Cache of discovered devices. """

View File

@ -9,7 +9,6 @@ from typing import (
Final, Final,
List, List,
Optional, Optional,
Set,
Union, Union,
Type, Type,
) )
@ -77,16 +76,6 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
_default_scan_duration: Final[float] = 10.0 _default_scan_duration: Final[float] = 10.0
""" Default duration of a discovery session (in seconds) """ """ Default duration of a discovery session (in seconds) """
_default_excluded_manufacturers = (
'Apple, Inc.',
'Google',
'Microsoft',
)
"""
Exclude beacons from these device manufacturers by default (main offenders
when it comes to Bluetooth device space pollution).
"""
def __init__( def __init__(
self, self,
interface: Optional[str] = None, interface: Optional[str] = None,
@ -94,9 +83,7 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
service_uuids: Optional[Collection[RawServiceClass]] = None, service_uuids: Optional[Collection[RawServiceClass]] = None,
scan_paused_on_start: bool = False, scan_paused_on_start: bool = False,
poll_interval: float = _default_scan_duration, poll_interval: float = _default_scan_duration,
excluded_manufacturers: Optional[ exclude_known_noisy_beacons: bool = True,
Collection[str]
] = _default_excluded_manufacturers,
**kwargs, **kwargs,
): ):
""" """
@ -109,14 +96,14 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
:param scan_paused_on_start: If ``True``, the plugin will not the :param scan_paused_on_start: If ``True``, the plugin will not the
scanning thread until :meth:`.scan_resume` is called (default: scanning thread until :meth:`.scan_resume` is called (default:
``False``). ``False``).
:param excluded_manufacturers: Exclude beacons from these device :param exclude_known_noisy_beacons: Exclude BLE beacons from devices
manufacturers. The default list includes Apple, Google and known for being very noisy. It mainly includes tracking services on
Microsoft, who are among the main offenders when it comes to Google, Apple, Microsoft and Samsung devices. These devices are
Bluetooth device address space pollution. Set this value to an also known for refreshing their MAC address very frequently, which
empty list if you want to get all beacons (e.g. because you need to may result in a large (and constantly increasing) list of devices.
communicate with Apple AirTags or Google devices over Bluetooth), Disable this flag if you need to track BLE beacons from these
but be warned that the list of discovered Bluetooth devices may devices, but beware that you may need periodically clean up your
dramatically increase over time. list of scanned devices.
""" """
kwargs['poll_interval'] = poll_interval kwargs['poll_interval'] = poll_interval
super().__init__(**kwargs) super().__init__(**kwargs)
@ -140,10 +127,8 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
""" """
Cache of the devices discovered by the plugin. Cache of the devices discovered by the plugin.
""" """
self._excluded_manufacturers: Set[str] = set(excluded_manufacturers or []) self._excluded_known_noisy_beacons = exclude_known_noisy_beacons
""" """ Exclude known noisy BLE beacons. """
Set of manufacturer strings whose associated devices should be ignored.
"""
self._managers: Dict[Type[BaseBluetoothManager], BaseBluetoothManager] = {} self._managers: Dict[Type[BaseBluetoothManager], BaseBluetoothManager] = {}
""" """
@ -183,6 +168,7 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
'device_queue': self._device_queue, 'device_queue': self._device_queue,
'service_uuids': list(map(BluetoothService.to_uuid, self._service_uuids)), 'service_uuids': list(map(BluetoothService.to_uuid, self._service_uuids)),
'device_cache': self._device_cache, 'device_cache': self._device_cache,
'exclude_known_noisy_beacons': self._excluded_known_noisy_beacons,
} }
self._managers = { self._managers = {
@ -488,11 +474,14 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
file = os.path.abspath(os.path.expanduser(file)) file = os.path.abspath(os.path.expanduser(file))
with open(file, 'rb') as f: with open(file, 'rb') as f:
binary_data = f.read() binary_data = f.read()
elif binary:
binary_data = base64.b64decode(
data.encode() if isinstance(data, str) else data
)
elif isinstance(data, str):
binary_data = data.encode()
else: else:
if binary: binary_data = data
binary_data = base64.b64decode(
data.encode() if isinstance(data, str) else data
)
sender = FileSender(self._managers[LegacyManager]) # type: ignore sender = FileSender(self._managers[LegacyManager]) # type: ignore
sender.send_file(file, device, binary_data) sender.send_file(file, device, binary_data)
@ -578,8 +567,7 @@ class BluetoothPlugin(RunnablePlugin, EntityManager):
continue continue
device = self._device_cache.add(device) device = self._device_cache.add(device)
if device.manufacturer not in self._excluded_manufacturers: self.publish_entities([device], callback=self._device_cache.add)
self.publish_entities([device], callback=self._device_cache.add)
finally: finally:
self.stop() self.stop()