Skip to content

Commit 65c54a6

Browse files
authored
feat!: eliminate the need to pass the new_info_callback (#21)
1 parent 5da9a7a commit 65c54a6

File tree

10 files changed

+81
-45
lines changed

10 files changed

+81
-45
lines changed

src/habluetooth/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
TRACKER_BUFFERING_WOBBLE_SECONDS,
55
AdvertisementTracker,
66
)
7-
from .base_scanner import BaseHaRemoteScanner, BaseHaScanner, BluetoothScannerDevice
7+
from .base_scanner import BaseHaRemoteScanner, BaseHaScanner
8+
from .central_manager import get_manager, set_manager
89
from .const import (
910
CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
1011
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
@@ -17,10 +18,9 @@
1718
BluetoothServiceInfo,
1819
BluetoothServiceInfoBleak,
1920
HaBluetoothConnector,
20-
get_manager,
21-
set_manager,
2221
)
2322
from .scanner import BluetoothScanningMode, HaScanner, ScannerStartError
23+
from .scanner_device import BluetoothScannerDevice
2424
from .wrappers import HaBleakClientWrapper, HaBleakScannerWrapper
2525

2626
__all__ = [

src/habluetooth/base_scanner.pxd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import cython
33

44
from .models cimport BluetoothServiceInfoBleak
5+
from .manager cimport BluetoothManager
56

67
cdef object NO_RSSI_VALUE
78
cdef object BluetoothServiceInfoBleak
@@ -22,11 +23,11 @@ cdef class BaseHaScanner:
2223
cdef public object _start_time
2324
cdef public object _cancel_watchdog
2425
cdef public object _loop
26+
cdef BluetoothManager _manager
2527

2628

2729
cdef class BaseHaRemoteScanner(BaseHaScanner):
2830

29-
cdef public object _new_info_callback
3031
cdef public dict _discovered_device_advertisement_datas
3132
cdef public dict _details
3233
cdef public float _expire_seconds

src/habluetooth/base_scanner.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33

44
import asyncio
55
import logging
6-
from collections.abc import Callable, Generator
6+
from collections.abc import Generator
77
from contextlib import contextmanager
8-
from dataclasses import dataclass
98
from typing import TYPE_CHECKING, Any, Final, final
109

1110
from bleak.backends.device import BLEDevice
@@ -14,6 +13,7 @@
1413
from bluetooth_adapters import DiscoveredDeviceAdvertisementData, adapter_human_name
1514
from bluetooth_data_tools import monotonic_time_coarse
1615

16+
from .central_manager import get_manager
1717
from .const import (
1818
CALLBACK_TYPE,
1919
CONNECTABLE_FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
@@ -31,15 +31,6 @@
3131
_str = str
3232

3333

34-
@dataclass(slots=True)
35-
class BluetoothScannerDevice:
36-
"""Data for a bluetooth device from a given scanner."""
37-
38-
scanner: BaseHaScanner
39-
ble_device: BLEDevice
40-
advertisement: AdvertisementData
41-
42-
4334
class BaseHaScanner:
4435
"""Base class for high availability BLE scanners."""
4536

@@ -55,6 +46,7 @@ class BaseHaScanner:
5546
"_start_time",
5647
"_cancel_watchdog",
5748
"_loop",
49+
"_manager",
5850
)
5951

6052
def __init__(
@@ -75,6 +67,7 @@ def __init__(
7567
self._start_time = 0.0
7668
self._cancel_watchdog: asyncio.TimerHandle | None = None
7769
self._loop: asyncio.AbstractEventLoop | None = None
70+
self._manager = get_manager()
7871

7972
def async_setup(self) -> CALLBACK_TYPE:
8073
"""Set up the scanner."""
@@ -191,7 +184,6 @@ class BaseHaRemoteScanner(BaseHaScanner):
191184
"""Base class for a high availability remote BLE scanner."""
192185

193186
__slots__ = (
194-
"_new_info_callback",
195187
"_discovered_device_advertisement_datas",
196188
"_details",
197189
"_expire_seconds",
@@ -203,13 +195,11 @@ def __init__(
203195
self,
204196
scanner_id: str,
205197
name: str,
206-
new_info_callback: Callable[[BluetoothServiceInfoBleak], None],
207198
connector: HaBluetoothConnector | None,
208199
connectable: bool,
209200
) -> None:
210201
"""Initialize the scanner."""
211202
super().__init__(scanner_id, name, connector)
212-
self._new_info_callback = new_info_callback
213203
self._discovered_device_advertisement_datas: dict[
214204
str, tuple[BLEDevice, AdvertisementData]
215205
] = {}
@@ -434,7 +424,7 @@ def _async_on_advertisement(
434424
advertisement_monotonic_time,
435425
)
436426
self._previous_service_info[address] = service_info
437-
self._new_info_callback(service_info)
427+
self._manager.scanner_adv_received(service_info)
438428

439429
async def async_diagnostics(self) -> dict[str, Any]:
440430
"""Return diagnostic information about the scanner."""

src/habluetooth/central_manager.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Central manager for bluetooth."""
2+
from __future__ import annotations
3+
4+
from typing import TYPE_CHECKING
5+
6+
if TYPE_CHECKING:
7+
from .manager import BluetoothManager
8+
9+
10+
class CentralBluetoothManager:
11+
"""Central Bluetooth Manager."""
12+
13+
manager: BluetoothManager | None = None
14+
15+
16+
def get_manager() -> BluetoothManager:
17+
"""Get the BluetoothManager."""
18+
if CentralBluetoothManager.manager is None:
19+
raise RuntimeError("BluetoothManager has not been set")
20+
return CentralBluetoothManager.manager
21+
22+
23+
def set_manager(manager: BluetoothManager) -> None:
24+
"""Set the BluetoothManager."""
25+
CentralBluetoothManager.manager = manager

src/habluetooth/manager.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,25 @@
1717
)
1818
from bluetooth_data_tools import monotonic_time_coarse
1919

20-
from habluetooth import TRACKER_BUFFERING_WOBBLE_SECONDS
21-
22-
from .advertisement_tracker import AdvertisementTracker
23-
from .base_scanner import BaseHaScanner, BluetoothScannerDevice
20+
from .advertisement_tracker import (
21+
TRACKER_BUFFERING_WOBBLE_SECONDS,
22+
AdvertisementTracker,
23+
)
2424
from .const import (
2525
CALLBACK_TYPE,
2626
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
2727
UNAVAILABLE_TRACK_SECONDS,
2828
)
2929
from .models import BluetoothServiceInfoBleak
30+
from .scanner_device import BluetoothScannerDevice
3031
from .usage import install_multiple_bleak_catcher, uninstall_multiple_bleak_catcher
3132

3233
if TYPE_CHECKING:
3334
from bleak.backends.device import BLEDevice
3435
from bleak.backends.scanner import AdvertisementData
3536

37+
from .base_scanner import BaseHaScanner
38+
3639

3740
FILTER_UUIDS: Final = "UUIDs"
3841

src/habluetooth/scanner.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ cdef class HaScanner(BaseHaScanner):
1515
cdef public object mac_address
1616
cdef public object mode
1717
cdef public object _start_stop_lock
18-
cdef public object _new_info_callback
1918
cdef public object _background_tasks
2019
cdef public object scanner
2120

src/habluetooth/scanner.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import asyncio
55
import logging
66
import platform
7-
from collections.abc import Callable
87
from typing import TYPE_CHECKING, Any, Coroutine
98

109
import bleak
@@ -123,7 +122,6 @@ def __init__(
123122
mode: BluetoothScanningMode,
124123
adapter: str,
125124
address: str,
126-
new_info_callback: Callable[[BluetoothServiceInfoBleak], None],
127125
) -> None:
128126
"""Init bluetooth discovery."""
129127
self.mac_address = address
@@ -132,7 +130,6 @@ def __init__(
132130
self.connectable = True
133131
self.mode = mode
134132
self._start_stop_lock = asyncio.Lock()
135-
self._new_info_callback = new_info_callback
136133
self.scanning = False
137134
self._background_tasks: set[asyncio.Task[Any]] = set()
138135
self.scanner: bleak.BleakScanner | None = None
@@ -199,7 +196,7 @@ def _async_detection_callback(
199196
name = advertisement_data.local_name or device.name or device.address
200197
if name is not None and type(name) is not str:
201198
name = str(name)
202-
self._new_info_callback(
199+
self._manager.scanner_adv_received(
203200
BluetoothServiceInfoBleak(
204201
name,
205202
device.address,

src/habluetooth/scanner_device.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Base classes for HA Bluetooth scanners for bluetooth."""
2+
from __future__ import annotations
3+
4+
from dataclasses import dataclass
5+
from typing import TYPE_CHECKING
6+
7+
from bleak.backends.device import BLEDevice
8+
from bleak.backends.scanner import AdvertisementData
9+
10+
if TYPE_CHECKING:
11+
from .base_scanner import BaseHaScanner
12+
13+
14+
@dataclass(slots=True)
15+
class BluetoothScannerDevice:
16+
"""Data for a bluetooth device from a given scanner."""
17+
18+
scanner: BaseHaScanner
19+
ble_device: BLEDevice
20+
advertisement: AdvertisementData

src/habluetooth/wrappers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,16 @@
2525
device_source,
2626
)
2727

28-
from .base_scanner import BaseHaScanner, BluetoothScannerDevice
28+
from .central_manager import get_manager
2929
from .const import CALLBACK_TYPE
30-
from .models import get_manager
30+
from .scanner_device import BluetoothScannerDevice
3131

3232
FILTER_UUIDS: Final = "UUIDs"
3333
_LOGGER = logging.getLogger(__name__)
3434

3535

3636
if TYPE_CHECKING:
37+
from .base_scanner import BaseHaScanner
3738
from .manager import BluetoothManager
3839

3940

tests/test_init.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
1-
from typing import Any
21
from unittest.mock import ANY
32

3+
import pytest
44
from bleak.backends.device import BLEDevice
55
from bleak.backends.scanner import AdvertisementData
6+
from bleak_retry_connector import BleakSlotManager
7+
from bluetooth_adapters import BluetoothAdapters
68

79
from habluetooth import (
810
BaseHaRemoteScanner,
911
BaseHaScanner,
12+
BluetoothManager,
1013
BluetoothScanningMode,
1114
HaBluetoothConnector,
1215
HaScanner,
16+
set_manager,
1317
)
1418

1519

20+
@pytest.fixture(scope="session", autouse=True)
21+
def manager():
22+
slot_manager = BleakSlotManager()
23+
bluetooth_adapters = BluetoothAdapters()
24+
set_manager(BluetoothManager(bluetooth_adapters, slot_manager))
25+
26+
1627
class MockBleakClient:
1728
pass
1829

@@ -36,20 +47,14 @@ def discovered_devices(self):
3647
def test_create_remote_scanner():
3748
connector = HaBluetoothConnector(MockBleakClient, "any", lambda: True)
3849

39-
def callback(data: Any) -> None:
40-
pass
41-
42-
scanner = BaseHaRemoteScanner("any", "any", callback, connector, True)
50+
scanner = BaseHaRemoteScanner("any", "any", connector, True)
4351
assert isinstance(scanner, BaseHaRemoteScanner)
4452

4553

4654
def test__async_on_advertisement():
4755
connector = HaBluetoothConnector(MockBleakClient, "any", lambda: True)
4856

49-
def callback(data: Any) -> None:
50-
pass
51-
52-
scanner = BaseHaRemoteScanner("any", "any", callback, connector, True)
57+
scanner = BaseHaRemoteScanner("any", "any", connector, True)
5358
details = scanner._details | {}
5459
scanner._async_on_advertisement(
5560
"AA:BB:CC:DD:EE:FF",
@@ -105,10 +110,5 @@ def callback(data: Any) -> None:
105110

106111

107112
def test_create_ha_scanner():
108-
def callback(data: Any) -> None:
109-
pass
110-
111-
scanner = HaScanner(
112-
BluetoothScanningMode.ACTIVE, "hci0", "AA:BB:CC:DD:EE:FF", callback
113-
)
113+
scanner = HaScanner(BluetoothScanningMode.ACTIVE, "hci0", "AA:BB:CC:DD:EE:FF")
114114
assert isinstance(scanner, HaScanner)

0 commit comments

Comments
 (0)