mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Improve bluetooth generic typing (#117157)
This commit is contained in:
parent
92254772ca
commit
4f4389ba85
@ -143,7 +143,7 @@ def _sensor_device_info_to_hass(
|
|||||||
|
|
||||||
def sensor_update_to_bluetooth_data_update(
|
def sensor_update_to_bluetooth_data_update(
|
||||||
adv: Aranet4Advertisement,
|
adv: Aranet4Advertisement,
|
||||||
) -> PassiveBluetoothDataUpdate:
|
) -> PassiveBluetoothDataUpdate[Any]:
|
||||||
"""Convert a sensor update to a Bluetooth data update."""
|
"""Convert a sensor update to a Bluetooth data update."""
|
||||||
data: dict[PassiveBluetoothEntityKey, Any] = {}
|
data: dict[PassiveBluetoothEntityKey, Any] = {}
|
||||||
names: dict[PassiveBluetoothEntityKey, str | None] = {}
|
names: dict[PassiveBluetoothEntityKey, str | None] = {}
|
||||||
@ -171,9 +171,9 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Aranet sensors."""
|
"""Set up the Aranet sensors."""
|
||||||
coordinator: PassiveBluetoothProcessorCoordinator = hass.data[DOMAIN][
|
coordinator: PassiveBluetoothProcessorCoordinator[Aranet4Advertisement] = hass.data[
|
||||||
entry.entry_id
|
DOMAIN
|
||||||
]
|
][entry.entry_id]
|
||||||
processor = PassiveBluetoothDataProcessor(sensor_update_to_bluetooth_data_update)
|
processor = PassiveBluetoothDataProcessor(sensor_update_to_bluetooth_data_update)
|
||||||
entry.async_on_unload(
|
entry.async_on_unload(
|
||||||
processor.async_add_entities_listener(
|
processor.async_add_entities_listener(
|
||||||
@ -184,7 +184,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class Aranet4BluetoothSensorEntity(
|
class Aranet4BluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, Aranet4Advertisement],
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of an Aranet sensor."""
|
"""Representation of an Aranet sensor."""
|
||||||
|
@ -134,7 +134,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class BlueMaestroBluetoothSensorEntity(
|
class BlueMaestroBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a BlueMaestro sensor."""
|
"""Representation of a BlueMaestro sensor."""
|
||||||
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable, Coroutine
|
from collections.abc import Callable, Coroutine
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Generic, TypeVar
|
from typing import Any, TypeVar
|
||||||
|
|
||||||
from bleak import BleakError
|
from bleak import BleakError
|
||||||
from bluetooth_data_tools import monotonic_time_coarse
|
from bluetooth_data_tools import monotonic_time_coarse
|
||||||
@ -21,12 +21,10 @@ from .passive_update_processor import PassiveBluetoothProcessorCoordinator
|
|||||||
POLL_DEFAULT_COOLDOWN = 10
|
POLL_DEFAULT_COOLDOWN = 10
|
||||||
POLL_DEFAULT_IMMEDIATE = True
|
POLL_DEFAULT_IMMEDIATE = True
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_DataT = TypeVar("_DataT")
|
||||||
|
|
||||||
|
|
||||||
class ActiveBluetoothProcessorCoordinator(
|
class ActiveBluetoothProcessorCoordinator(PassiveBluetoothProcessorCoordinator[_DataT]):
|
||||||
Generic[_T], PassiveBluetoothProcessorCoordinator[_T]
|
|
||||||
):
|
|
||||||
"""A processor coordinator that parses passive data.
|
"""A processor coordinator that parses passive data.
|
||||||
|
|
||||||
Parses passive data from advertisements but can also poll.
|
Parses passive data from advertisements but can also poll.
|
||||||
@ -63,11 +61,11 @@ class ActiveBluetoothProcessorCoordinator(
|
|||||||
*,
|
*,
|
||||||
address: str,
|
address: str,
|
||||||
mode: BluetoothScanningMode,
|
mode: BluetoothScanningMode,
|
||||||
update_method: Callable[[BluetoothServiceInfoBleak], _T],
|
update_method: Callable[[BluetoothServiceInfoBleak], _DataT],
|
||||||
needs_poll_method: Callable[[BluetoothServiceInfoBleak, float | None], bool],
|
needs_poll_method: Callable[[BluetoothServiceInfoBleak, float | None], bool],
|
||||||
poll_method: Callable[
|
poll_method: Callable[
|
||||||
[BluetoothServiceInfoBleak],
|
[BluetoothServiceInfoBleak],
|
||||||
Coroutine[Any, Any, _T],
|
Coroutine[Any, Any, _DataT],
|
||||||
]
|
]
|
||||||
| None = None,
|
| None = None,
|
||||||
poll_debouncer: Debouncer[Coroutine[Any, Any, None]] | None = None,
|
poll_debouncer: Debouncer[Coroutine[Any, Any, None]] | None = None,
|
||||||
@ -110,7 +108,7 @@ class ActiveBluetoothProcessorCoordinator(
|
|||||||
|
|
||||||
async def _async_poll_data(
|
async def _async_poll_data(
|
||||||
self, last_service_info: BluetoothServiceInfoBleak
|
self, last_service_info: BluetoothServiceInfoBleak
|
||||||
) -> _T:
|
) -> _DataT:
|
||||||
"""Fetch the latest data from the source."""
|
"""Fetch the latest data from the source."""
|
||||||
if self._poll_method is None:
|
if self._poll_method is None:
|
||||||
raise NotImplementedError("Poll method not implemented")
|
raise NotImplementedError("Poll method not implemented")
|
||||||
|
@ -6,7 +6,7 @@ import dataclasses
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from functools import cache
|
from functools import cache
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeVar, cast
|
from typing import TYPE_CHECKING, Any, Generic, Self, TypedDict, TypeVar, cast
|
||||||
|
|
||||||
from habluetooth import BluetoothScanningMode
|
from habluetooth import BluetoothScanningMode
|
||||||
|
|
||||||
@ -42,7 +42,9 @@ STORAGE_KEY = "bluetooth.passive_update_processor"
|
|||||||
STORAGE_VERSION = 1
|
STORAGE_VERSION = 1
|
||||||
STORAGE_SAVE_INTERVAL = timedelta(minutes=15)
|
STORAGE_SAVE_INTERVAL = timedelta(minutes=15)
|
||||||
PASSIVE_UPDATE_PROCESSOR = "passive_update_processor"
|
PASSIVE_UPDATE_PROCESSOR = "passive_update_processor"
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
_DataT = TypeVar("_DataT")
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(slots=True, frozen=True)
|
@dataclasses.dataclass(slots=True, frozen=True)
|
||||||
@ -73,7 +75,7 @@ class PassiveBluetoothEntityKey:
|
|||||||
class PassiveBluetoothProcessorData:
|
class PassiveBluetoothProcessorData:
|
||||||
"""Data for the passive bluetooth processor."""
|
"""Data for the passive bluetooth processor."""
|
||||||
|
|
||||||
coordinators: set[PassiveBluetoothProcessorCoordinator]
|
coordinators: set[PassiveBluetoothProcessorCoordinator[Any]]
|
||||||
all_restore_data: dict[str, dict[str, RestoredPassiveBluetoothDataUpdate]]
|
all_restore_data: dict[str, dict[str, RestoredPassiveBluetoothDataUpdate]]
|
||||||
|
|
||||||
|
|
||||||
@ -220,7 +222,7 @@ class PassiveBluetoothDataUpdate(Generic[_T]):
|
|||||||
|
|
||||||
|
|
||||||
def async_register_coordinator_for_restore(
|
def async_register_coordinator_for_restore(
|
||||||
hass: HomeAssistant, coordinator: PassiveBluetoothProcessorCoordinator
|
hass: HomeAssistant, coordinator: PassiveBluetoothProcessorCoordinator[Any]
|
||||||
) -> CALLBACK_TYPE:
|
) -> CALLBACK_TYPE:
|
||||||
"""Register a coordinator to have its processors data restored."""
|
"""Register a coordinator to have its processors data restored."""
|
||||||
data: PassiveBluetoothProcessorData = hass.data[PASSIVE_UPDATE_PROCESSOR]
|
data: PassiveBluetoothProcessorData = hass.data[PASSIVE_UPDATE_PROCESSOR]
|
||||||
@ -242,7 +244,7 @@ async def async_setup(hass: HomeAssistant) -> None:
|
|||||||
storage: Store[dict[str, dict[str, RestoredPassiveBluetoothDataUpdate]]] = Store(
|
storage: Store[dict[str, dict[str, RestoredPassiveBluetoothDataUpdate]]] = Store(
|
||||||
hass, STORAGE_VERSION, STORAGE_KEY
|
hass, STORAGE_VERSION, STORAGE_KEY
|
||||||
)
|
)
|
||||||
coordinators: set[PassiveBluetoothProcessorCoordinator] = set()
|
coordinators: set[PassiveBluetoothProcessorCoordinator[Any]] = set()
|
||||||
all_restore_data: dict[str, dict[str, RestoredPassiveBluetoothDataUpdate]] = (
|
all_restore_data: dict[str, dict[str, RestoredPassiveBluetoothDataUpdate]] = (
|
||||||
await storage.async_load() or {}
|
await storage.async_load() or {}
|
||||||
)
|
)
|
||||||
@ -276,7 +278,7 @@ async def async_setup(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
|
|
||||||
class PassiveBluetoothProcessorCoordinator(
|
class PassiveBluetoothProcessorCoordinator(
|
||||||
Generic[_T], BasePassiveBluetoothCoordinator
|
Generic[_DataT], BasePassiveBluetoothCoordinator
|
||||||
):
|
):
|
||||||
"""Passive bluetooth processor coordinator for bluetooth advertisements.
|
"""Passive bluetooth processor coordinator for bluetooth advertisements.
|
||||||
|
|
||||||
@ -294,12 +296,12 @@ class PassiveBluetoothProcessorCoordinator(
|
|||||||
logger: logging.Logger,
|
logger: logging.Logger,
|
||||||
address: str,
|
address: str,
|
||||||
mode: BluetoothScanningMode,
|
mode: BluetoothScanningMode,
|
||||||
update_method: Callable[[BluetoothServiceInfoBleak], _T],
|
update_method: Callable[[BluetoothServiceInfoBleak], _DataT],
|
||||||
connectable: bool = False,
|
connectable: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the coordinator."""
|
"""Initialize the coordinator."""
|
||||||
super().__init__(hass, logger, address, mode, connectable)
|
super().__init__(hass, logger, address, mode, connectable)
|
||||||
self._processors: list[PassiveBluetoothDataProcessor] = []
|
self._processors: list[PassiveBluetoothDataProcessor[Any, _DataT]] = []
|
||||||
self._update_method = update_method
|
self._update_method = update_method
|
||||||
self.last_update_success = True
|
self.last_update_success = True
|
||||||
self.restore_data: dict[str, RestoredPassiveBluetoothDataUpdate] = {}
|
self.restore_data: dict[str, RestoredPassiveBluetoothDataUpdate] = {}
|
||||||
@ -327,7 +329,7 @@ class PassiveBluetoothProcessorCoordinator(
|
|||||||
@callback
|
@callback
|
||||||
def async_register_processor(
|
def async_register_processor(
|
||||||
self,
|
self,
|
||||||
processor: PassiveBluetoothDataProcessor,
|
processor: PassiveBluetoothDataProcessor[Any, _DataT],
|
||||||
entity_description_class: type[EntityDescription] | None = None,
|
entity_description_class: type[EntityDescription] | None = None,
|
||||||
) -> Callable[[], None]:
|
) -> Callable[[], None]:
|
||||||
"""Register a processor that subscribes to updates."""
|
"""Register a processor that subscribes to updates."""
|
||||||
@ -388,11 +390,11 @@ class PassiveBluetoothProcessorCoordinator(
|
|||||||
|
|
||||||
_PassiveBluetoothDataProcessorT = TypeVar(
|
_PassiveBluetoothDataProcessorT = TypeVar(
|
||||||
"_PassiveBluetoothDataProcessorT",
|
"_PassiveBluetoothDataProcessorT",
|
||||||
bound="PassiveBluetoothDataProcessor[Any]",
|
bound="PassiveBluetoothDataProcessor[Any, Any]",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PassiveBluetoothDataProcessor(Generic[_T]):
|
class PassiveBluetoothDataProcessor(Generic[_T, _DataT]):
|
||||||
"""Passive bluetooth data processor for bluetooth advertisements.
|
"""Passive bluetooth data processor for bluetooth advertisements.
|
||||||
|
|
||||||
The processor is responsible for keeping track of the bluetooth data
|
The processor is responsible for keeping track of the bluetooth data
|
||||||
@ -413,7 +415,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
|||||||
is available in the devices, entity_data, and entity_descriptions attributes.
|
is available in the devices, entity_data, and entity_descriptions attributes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
coordinator: PassiveBluetoothProcessorCoordinator
|
coordinator: PassiveBluetoothProcessorCoordinator[_DataT]
|
||||||
data: PassiveBluetoothDataUpdate[_T]
|
data: PassiveBluetoothDataUpdate[_T]
|
||||||
entity_names: dict[PassiveBluetoothEntityKey, str | None]
|
entity_names: dict[PassiveBluetoothEntityKey, str | None]
|
||||||
entity_data: dict[PassiveBluetoothEntityKey, _T]
|
entity_data: dict[PassiveBluetoothEntityKey, _T]
|
||||||
@ -423,7 +425,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
update_method: Callable[[_T], PassiveBluetoothDataUpdate[_T]],
|
update_method: Callable[[_DataT], PassiveBluetoothDataUpdate[_T]],
|
||||||
restore_key: str | None = None,
|
restore_key: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the coordinator."""
|
"""Initialize the coordinator."""
|
||||||
@ -444,7 +446,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
|||||||
@callback
|
@callback
|
||||||
def async_register_coordinator(
|
def async_register_coordinator(
|
||||||
self,
|
self,
|
||||||
coordinator: PassiveBluetoothProcessorCoordinator,
|
coordinator: PassiveBluetoothProcessorCoordinator[_DataT],
|
||||||
entity_description_class: type[EntityDescription] | None,
|
entity_description_class: type[EntityDescription] | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register a coordinator."""
|
"""Register a coordinator."""
|
||||||
@ -482,7 +484,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
|||||||
@callback
|
@callback
|
||||||
def async_add_entities_listener(
|
def async_add_entities_listener(
|
||||||
self,
|
self,
|
||||||
entity_class: type[PassiveBluetoothProcessorEntity],
|
entity_class: type[PassiveBluetoothProcessorEntity[Self]],
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> Callable[[], None]:
|
) -> Callable[[], None]:
|
||||||
"""Add a listener for new entities."""
|
"""Add a listener for new entities."""
|
||||||
@ -495,7 +497,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
|||||||
"""Listen for new entities."""
|
"""Listen for new entities."""
|
||||||
if data is None or created.issuperset(data.entity_descriptions):
|
if data is None or created.issuperset(data.entity_descriptions):
|
||||||
return
|
return
|
||||||
entities: list[PassiveBluetoothProcessorEntity] = []
|
entities: list[PassiveBluetoothProcessorEntity[Self]] = []
|
||||||
for entity_key, description in data.entity_descriptions.items():
|
for entity_key, description in data.entity_descriptions.items():
|
||||||
if entity_key not in created:
|
if entity_key not in created:
|
||||||
entities.append(entity_class(self, entity_key, description))
|
entities.append(entity_class(self, entity_key, description))
|
||||||
@ -578,7 +580,7 @@ class PassiveBluetoothDataProcessor(Generic[_T]):
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_handle_update(
|
def async_handle_update(
|
||||||
self, update: _T, was_available: bool | None = None
|
self, update: _DataT, was_available: bool | None = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle a Bluetooth event."""
|
"""Handle a Bluetooth event."""
|
||||||
try:
|
try:
|
||||||
@ -666,7 +668,8 @@ class PassiveBluetoothProcessorEntity(Entity, Generic[_PassiveBluetoothDataProce
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_processor_update(
|
def _handle_processor_update(
|
||||||
self, new_data: PassiveBluetoothDataUpdate | None
|
self,
|
||||||
|
new_data: PassiveBluetoothDataUpdate[_PassiveBluetoothDataProcessorT] | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle updated data from the processor."""
|
"""Handle updated data from the processor."""
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -145,7 +145,7 @@ BINARY_SENSOR_DESCRIPTIONS = {
|
|||||||
|
|
||||||
def sensor_update_to_bluetooth_data_update(
|
def sensor_update_to_bluetooth_data_update(
|
||||||
sensor_update: SensorUpdate,
|
sensor_update: SensorUpdate,
|
||||||
) -> PassiveBluetoothDataUpdate:
|
) -> PassiveBluetoothDataUpdate[bool | None]:
|
||||||
"""Convert a binary sensor update to a bluetooth data update."""
|
"""Convert a binary sensor update to a bluetooth data update."""
|
||||||
return PassiveBluetoothDataUpdate(
|
return PassiveBluetoothDataUpdate(
|
||||||
devices={
|
devices={
|
||||||
@ -193,7 +193,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class BTHomeBluetoothBinarySensorEntity(
|
class BTHomeBluetoothBinarySensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[BTHomePassiveBluetoothDataProcessor],
|
PassiveBluetoothProcessorEntity[BTHomePassiveBluetoothDataProcessor[bool | None]],
|
||||||
BinarySensorEntity,
|
BinarySensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a BTHome binary sensor."""
|
"""Representation of a BTHome binary sensor."""
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from typing import Any
|
from typing import TypeVar
|
||||||
|
|
||||||
from bthome_ble import BTHomeBluetoothDeviceData
|
from bthome_ble import BTHomeBluetoothDeviceData, SensorUpdate
|
||||||
|
|
||||||
from homeassistant.components.bluetooth import (
|
from homeassistant.components.bluetooth import (
|
||||||
BluetoothScanningMode,
|
BluetoothScanningMode,
|
||||||
@ -19,8 +19,12 @@ from homeassistant.core import HomeAssistant
|
|||||||
|
|
||||||
from .const import CONF_SLEEPY_DEVICE
|
from .const import CONF_SLEEPY_DEVICE
|
||||||
|
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
class BTHomePassiveBluetoothProcessorCoordinator(PassiveBluetoothProcessorCoordinator):
|
|
||||||
|
class BTHomePassiveBluetoothProcessorCoordinator(
|
||||||
|
PassiveBluetoothProcessorCoordinator[SensorUpdate]
|
||||||
|
):
|
||||||
"""Define a BTHome Bluetooth Passive Update Processor Coordinator."""
|
"""Define a BTHome Bluetooth Passive Update Processor Coordinator."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -29,7 +33,7 @@ class BTHomePassiveBluetoothProcessorCoordinator(PassiveBluetoothProcessorCoordi
|
|||||||
logger: Logger,
|
logger: Logger,
|
||||||
address: str,
|
address: str,
|
||||||
mode: BluetoothScanningMode,
|
mode: BluetoothScanningMode,
|
||||||
update_method: Callable[[BluetoothServiceInfoBleak], Any],
|
update_method: Callable[[BluetoothServiceInfoBleak], SensorUpdate],
|
||||||
device_data: BTHomeBluetoothDeviceData,
|
device_data: BTHomeBluetoothDeviceData,
|
||||||
discovered_event_classes: set[str],
|
discovered_event_classes: set[str],
|
||||||
entry: ConfigEntry,
|
entry: ConfigEntry,
|
||||||
@ -47,7 +51,9 @@ class BTHomePassiveBluetoothProcessorCoordinator(PassiveBluetoothProcessorCoordi
|
|||||||
return self.entry.data.get(CONF_SLEEPY_DEVICE, self.device_data.sleepy_device)
|
return self.entry.data.get(CONF_SLEEPY_DEVICE, self.device_data.sleepy_device)
|
||||||
|
|
||||||
|
|
||||||
class BTHomePassiveBluetoothDataProcessor(PassiveBluetoothDataProcessor):
|
class BTHomePassiveBluetoothDataProcessor(
|
||||||
|
PassiveBluetoothDataProcessor[_T, SensorUpdate]
|
||||||
|
):
|
||||||
"""Define a BTHome Bluetooth Passive Update Data Processor."""
|
"""Define a BTHome Bluetooth Passive Update Data Processor."""
|
||||||
|
|
||||||
coordinator: BTHomePassiveBluetoothProcessorCoordinator
|
coordinator: BTHomePassiveBluetoothProcessorCoordinator
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from bthome_ble import SensorDeviceClass as BTHomeSensorDeviceClass, SensorUpdate, Units
|
from bthome_ble import SensorDeviceClass as BTHomeSensorDeviceClass, SensorUpdate, Units
|
||||||
from bthome_ble.const import (
|
from bthome_ble.const import (
|
||||||
ExtendedSensorDeviceClass as BTHomeExtendedSensorDeviceClass,
|
ExtendedSensorDeviceClass as BTHomeExtendedSensorDeviceClass,
|
||||||
@ -363,7 +365,7 @@ SENSOR_DESCRIPTIONS = {
|
|||||||
|
|
||||||
def sensor_update_to_bluetooth_data_update(
|
def sensor_update_to_bluetooth_data_update(
|
||||||
sensor_update: SensorUpdate,
|
sensor_update: SensorUpdate,
|
||||||
) -> PassiveBluetoothDataUpdate:
|
) -> PassiveBluetoothDataUpdate[float | None]:
|
||||||
"""Convert a sensor update to a bluetooth data update."""
|
"""Convert a sensor update to a bluetooth data update."""
|
||||||
return PassiveBluetoothDataUpdate(
|
return PassiveBluetoothDataUpdate(
|
||||||
devices={
|
devices={
|
||||||
@ -378,7 +380,9 @@ def sensor_update_to_bluetooth_data_update(
|
|||||||
if description.device_class
|
if description.device_class
|
||||||
},
|
},
|
||||||
entity_data={
|
entity_data={
|
||||||
device_key_to_bluetooth_entity_key(device_key): sensor_values.native_value
|
device_key_to_bluetooth_entity_key(device_key): cast(
|
||||||
|
float | None, sensor_values.native_value
|
||||||
|
)
|
||||||
for device_key, sensor_values in sensor_update.entity_values.items()
|
for device_key, sensor_values in sensor_update.entity_values.items()
|
||||||
},
|
},
|
||||||
entity_names={
|
entity_names={
|
||||||
@ -411,7 +415,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class BTHomeBluetoothSensorEntity(
|
class BTHomeBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[BTHomePassiveBluetoothDataProcessor],
|
PassiveBluetoothProcessorEntity[BTHomePassiveBluetoothDataProcessor[float | None]],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a BTHome BLE sensor."""
|
"""Representation of a BTHome BLE sensor."""
|
||||||
|
@ -124,7 +124,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
class GoveeBluetoothSensorEntity(
|
class GoveeBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[
|
PassiveBluetoothProcessorEntity[
|
||||||
PassiveBluetoothDataProcessor[float | int | str | None]
|
PassiveBluetoothDataProcessor[float | int | str | None, SensorUpdate]
|
||||||
],
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
|
@ -114,7 +114,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class INKBIRDBluetoothSensorEntity(
|
class INKBIRDBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a inkbird ble sensor."""
|
"""Representation of a inkbird ble sensor."""
|
||||||
|
@ -126,7 +126,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class KegtronBluetoothSensorEntity(
|
class KegtronBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Kegtron sensor."""
|
"""Representation of a Kegtron sensor."""
|
||||||
|
@ -125,7 +125,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class LeaoneBluetoothSensorEntity(
|
class LeaoneBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Leaone sensor."""
|
"""Representation of a Leaone sensor."""
|
||||||
|
@ -121,7 +121,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class MoatBluetoothSensorEntity(
|
class MoatBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a moat ble sensor."""
|
"""Representation of a moat ble sensor."""
|
||||||
|
@ -133,7 +133,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class MopekaBluetoothSensorEntity(
|
class MopekaBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Mopeka sensor."""
|
"""Representation of a Mopeka sensor."""
|
||||||
|
@ -128,7 +128,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class OralBBluetoothSensorEntity(
|
class OralBBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[str | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[str | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a OralB sensor."""
|
"""Representation of a OralB sensor."""
|
||||||
|
@ -94,7 +94,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class QingpingBluetoothSensorEntity(
|
class QingpingBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[bool | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[bool | None, SensorUpdate]
|
||||||
|
],
|
||||||
BinarySensorEntity,
|
BinarySensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Qingping binary sensor."""
|
"""Representation of a Qingping binary sensor."""
|
||||||
|
@ -162,7 +162,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class QingpingBluetoothSensorEntity(
|
class QingpingBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Qingping sensor."""
|
"""Representation of a Qingping sensor."""
|
||||||
|
@ -115,7 +115,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class RAPTPillBluetoothSensorEntity(
|
class RAPTPillBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a RAPT Pill BLE sensor."""
|
"""Representation of a RAPT Pill BLE sensor."""
|
||||||
|
@ -142,7 +142,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class RuuvitagBluetoothSensorEntity(
|
class RuuvitagBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Ruuvitag BLE sensor."""
|
"""Representation of a Ruuvitag BLE sensor."""
|
||||||
|
@ -122,7 +122,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class SensirionBluetoothSensorEntity(
|
class SensirionBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Sensirion BLE sensor."""
|
"""Representation of a Sensirion BLE sensor."""
|
||||||
|
@ -127,7 +127,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class SensorProBluetoothSensorEntity(
|
class SensorProBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a SensorPro sensor."""
|
"""Representation of a SensorPro sensor."""
|
||||||
|
@ -117,7 +117,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class SensorPushBluetoothSensorEntity(
|
class SensorPushBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a sensorpush ble sensor."""
|
"""Representation of a sensorpush ble sensor."""
|
||||||
|
@ -129,7 +129,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class ThermoBeaconBluetoothSensorEntity(
|
class ThermoBeaconBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a ThermoBeacon sensor."""
|
"""Representation of a ThermoBeacon sensor."""
|
||||||
|
@ -127,7 +127,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class ThermoProBluetoothSensorEntity(
|
class ThermoProBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a thermopro ble sensor."""
|
"""Representation of a thermopro ble sensor."""
|
||||||
|
@ -102,7 +102,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class TiltBluetoothSensorEntity(
|
class TiltBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[PassiveBluetoothDataProcessor[float | int | None]],
|
PassiveBluetoothProcessorEntity[
|
||||||
|
PassiveBluetoothDataProcessor[float | int | None, SensorUpdate]
|
||||||
|
],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Tilt Hydrometer BLE sensor."""
|
"""Representation of a Tilt Hydrometer BLE sensor."""
|
||||||
|
@ -107,7 +107,7 @@ BINARY_SENSOR_DESCRIPTIONS = {
|
|||||||
|
|
||||||
def sensor_update_to_bluetooth_data_update(
|
def sensor_update_to_bluetooth_data_update(
|
||||||
sensor_update: SensorUpdate,
|
sensor_update: SensorUpdate,
|
||||||
) -> PassiveBluetoothDataUpdate:
|
) -> PassiveBluetoothDataUpdate[bool | None]:
|
||||||
"""Convert a sensor update to a bluetooth data update."""
|
"""Convert a sensor update to a bluetooth data update."""
|
||||||
return PassiveBluetoothDataUpdate(
|
return PassiveBluetoothDataUpdate(
|
||||||
devices={
|
devices={
|
||||||
@ -155,7 +155,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class XiaomiBluetoothSensorEntity(
|
class XiaomiBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[XiaomiPassiveBluetoothDataProcessor],
|
PassiveBluetoothProcessorEntity[XiaomiPassiveBluetoothDataProcessor[bool | None]],
|
||||||
BinarySensorEntity,
|
BinarySensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a Xiaomi binary sensor."""
|
"""Representation of a Xiaomi binary sensor."""
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
from collections.abc import Callable, Coroutine
|
from collections.abc import Callable, Coroutine
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from typing import Any
|
from typing import Any, TypeVar
|
||||||
|
|
||||||
from xiaomi_ble import XiaomiBluetoothDeviceData
|
from xiaomi_ble import SensorUpdate, XiaomiBluetoothDeviceData
|
||||||
|
|
||||||
from homeassistant.components.bluetooth import (
|
from homeassistant.components.bluetooth import (
|
||||||
BluetoothScanningMode,
|
BluetoothScanningMode,
|
||||||
@ -22,8 +22,12 @@ from homeassistant.helpers.debounce import Debouncer
|
|||||||
|
|
||||||
from .const import CONF_SLEEPY_DEVICE
|
from .const import CONF_SLEEPY_DEVICE
|
||||||
|
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
class XiaomiActiveBluetoothProcessorCoordinator(ActiveBluetoothProcessorCoordinator):
|
|
||||||
|
class XiaomiActiveBluetoothProcessorCoordinator(
|
||||||
|
ActiveBluetoothProcessorCoordinator[SensorUpdate]
|
||||||
|
):
|
||||||
"""Define a Xiaomi Bluetooth Active Update Processor Coordinator."""
|
"""Define a Xiaomi Bluetooth Active Update Processor Coordinator."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -33,13 +37,13 @@ class XiaomiActiveBluetoothProcessorCoordinator(ActiveBluetoothProcessorCoordina
|
|||||||
*,
|
*,
|
||||||
address: str,
|
address: str,
|
||||||
mode: BluetoothScanningMode,
|
mode: BluetoothScanningMode,
|
||||||
update_method: Callable[[BluetoothServiceInfoBleak], Any],
|
update_method: Callable[[BluetoothServiceInfoBleak], SensorUpdate],
|
||||||
needs_poll_method: Callable[[BluetoothServiceInfoBleak, float | None], bool],
|
needs_poll_method: Callable[[BluetoothServiceInfoBleak, float | None], bool],
|
||||||
device_data: XiaomiBluetoothDeviceData,
|
device_data: XiaomiBluetoothDeviceData,
|
||||||
discovered_event_classes: set[str],
|
discovered_event_classes: set[str],
|
||||||
poll_method: Callable[
|
poll_method: Callable[
|
||||||
[BluetoothServiceInfoBleak],
|
[BluetoothServiceInfoBleak],
|
||||||
Coroutine[Any, Any, Any],
|
Coroutine[Any, Any, SensorUpdate],
|
||||||
]
|
]
|
||||||
| None = None,
|
| None = None,
|
||||||
poll_debouncer: Debouncer[Coroutine[Any, Any, None]] | None = None,
|
poll_debouncer: Debouncer[Coroutine[Any, Any, None]] | None = None,
|
||||||
@ -68,7 +72,9 @@ class XiaomiActiveBluetoothProcessorCoordinator(ActiveBluetoothProcessorCoordina
|
|||||||
return self.entry.data.get(CONF_SLEEPY_DEVICE, self.device_data.sleepy_device)
|
return self.entry.data.get(CONF_SLEEPY_DEVICE, self.device_data.sleepy_device)
|
||||||
|
|
||||||
|
|
||||||
class XiaomiPassiveBluetoothDataProcessor(PassiveBluetoothDataProcessor):
|
class XiaomiPassiveBluetoothDataProcessor(
|
||||||
|
PassiveBluetoothDataProcessor[_T, SensorUpdate]
|
||||||
|
):
|
||||||
"""Define a Xiaomi Bluetooth Passive Update Data Processor."""
|
"""Define a Xiaomi Bluetooth Passive Update Data Processor."""
|
||||||
|
|
||||||
coordinator: XiaomiActiveBluetoothProcessorCoordinator
|
coordinator: XiaomiActiveBluetoothProcessorCoordinator
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from xiaomi_ble import DeviceClass, SensorUpdate, Units
|
from xiaomi_ble import DeviceClass, SensorUpdate, Units
|
||||||
from xiaomi_ble.parser import ExtendedSensorDeviceClass
|
from xiaomi_ble.parser import ExtendedSensorDeviceClass
|
||||||
|
|
||||||
@ -162,7 +164,7 @@ SENSOR_DESCRIPTIONS = {
|
|||||||
|
|
||||||
def sensor_update_to_bluetooth_data_update(
|
def sensor_update_to_bluetooth_data_update(
|
||||||
sensor_update: SensorUpdate,
|
sensor_update: SensorUpdate,
|
||||||
) -> PassiveBluetoothDataUpdate:
|
) -> PassiveBluetoothDataUpdate[float | None]:
|
||||||
"""Convert a sensor update to a bluetooth data update."""
|
"""Convert a sensor update to a bluetooth data update."""
|
||||||
return PassiveBluetoothDataUpdate(
|
return PassiveBluetoothDataUpdate(
|
||||||
devices={
|
devices={
|
||||||
@ -177,7 +179,9 @@ def sensor_update_to_bluetooth_data_update(
|
|||||||
if description.device_class
|
if description.device_class
|
||||||
},
|
},
|
||||||
entity_data={
|
entity_data={
|
||||||
device_key_to_bluetooth_entity_key(device_key): sensor_values.native_value
|
device_key_to_bluetooth_entity_key(device_key): cast(
|
||||||
|
float | None, sensor_values.native_value
|
||||||
|
)
|
||||||
for device_key, sensor_values in sensor_update.entity_values.items()
|
for device_key, sensor_values in sensor_update.entity_values.items()
|
||||||
},
|
},
|
||||||
entity_names={
|
entity_names={
|
||||||
@ -210,7 +214,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
|
|
||||||
class XiaomiBluetoothSensorEntity(
|
class XiaomiBluetoothSensorEntity(
|
||||||
PassiveBluetoothProcessorEntity[XiaomiPassiveBluetoothDataProcessor],
|
PassiveBluetoothProcessorEntity[XiaomiPassiveBluetoothDataProcessor[float | None]],
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
):
|
):
|
||||||
"""Representation of a xiaomi ble sensor."""
|
"""Representation of a xiaomi ble sensor."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user