mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Fix esphome state mapping (#74337)
This commit is contained in:
parent
30a5df5895
commit
40ed44cbea
@ -558,7 +558,7 @@ async def platform_async_setup_entry(
|
|||||||
entry_data: RuntimeEntryData = DomainData.get(hass).get_entry_data(entry)
|
entry_data: RuntimeEntryData = DomainData.get(hass).get_entry_data(entry)
|
||||||
entry_data.info[component_key] = {}
|
entry_data.info[component_key] = {}
|
||||||
entry_data.old_info[component_key] = {}
|
entry_data.old_info[component_key] = {}
|
||||||
entry_data.state[component_key] = {}
|
entry_data.state.setdefault(state_type, {})
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_list_entities(infos: list[EntityInfo]) -> None:
|
def async_list_entities(infos: list[EntityInfo]) -> None:
|
||||||
@ -578,7 +578,7 @@ async def platform_async_setup_entry(
|
|||||||
old_infos.pop(info.key)
|
old_infos.pop(info.key)
|
||||||
else:
|
else:
|
||||||
# Create new entity
|
# Create new entity
|
||||||
entity = entity_type(entry_data, component_key, info.key)
|
entity = entity_type(entry_data, component_key, info.key, state_type)
|
||||||
add_entities.append(entity)
|
add_entities.append(entity)
|
||||||
new_infos[info.key] = info
|
new_infos[info.key] = info
|
||||||
|
|
||||||
@ -677,12 +677,17 @@ class EsphomeEntity(Entity, Generic[_InfoT, _StateT]):
|
|||||||
"""Define a base esphome entity."""
|
"""Define a base esphome entity."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, entry_data: RuntimeEntryData, component_key: str, key: int
|
self,
|
||||||
|
entry_data: RuntimeEntryData,
|
||||||
|
component_key: str,
|
||||||
|
key: int,
|
||||||
|
state_type: type[_StateT],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self._entry_data = entry_data
|
self._entry_data = entry_data
|
||||||
self._component_key = component_key
|
self._component_key = component_key
|
||||||
self._key = key
|
self._key = key
|
||||||
|
self._state_type = state_type
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
@ -707,7 +712,7 @@ class EsphomeEntity(Entity, Generic[_InfoT, _StateT]):
|
|||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self._entry_data.async_subscribe_state_update(
|
self._entry_data.async_subscribe_state_update(
|
||||||
self._component_key, self._key, self._on_state_update
|
self._state_type, self._key, self._on_state_update
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -755,11 +760,11 @@ class EsphomeEntity(Entity, Generic[_InfoT, _StateT]):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def _state(self) -> _StateT:
|
def _state(self) -> _StateT:
|
||||||
return cast(_StateT, self._entry_data.state[self._component_key][self._key])
|
return cast(_StateT, self._entry_data.state[self._state_type][self._key])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _has_state(self) -> bool:
|
def _has_state(self) -> bool:
|
||||||
return self._key in self._entry_data.state[self._component_key]
|
return self._key in self._entry_data.state[self._state_type]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
|
@ -12,34 +12,21 @@ from aioesphomeapi import (
|
|||||||
APIClient,
|
APIClient,
|
||||||
APIVersion,
|
APIVersion,
|
||||||
BinarySensorInfo,
|
BinarySensorInfo,
|
||||||
BinarySensorState,
|
|
||||||
CameraInfo,
|
CameraInfo,
|
||||||
CameraState,
|
|
||||||
ClimateInfo,
|
ClimateInfo,
|
||||||
ClimateState,
|
|
||||||
CoverInfo,
|
CoverInfo,
|
||||||
CoverState,
|
|
||||||
DeviceInfo,
|
DeviceInfo,
|
||||||
EntityInfo,
|
EntityInfo,
|
||||||
EntityState,
|
EntityState,
|
||||||
FanInfo,
|
FanInfo,
|
||||||
FanState,
|
|
||||||
LightInfo,
|
LightInfo,
|
||||||
LightState,
|
|
||||||
LockInfo,
|
LockInfo,
|
||||||
LockState,
|
|
||||||
MediaPlayerInfo,
|
MediaPlayerInfo,
|
||||||
MediaPlayerState,
|
|
||||||
NumberInfo,
|
NumberInfo,
|
||||||
NumberState,
|
|
||||||
SelectInfo,
|
SelectInfo,
|
||||||
SelectState,
|
|
||||||
SensorInfo,
|
SensorInfo,
|
||||||
SensorState,
|
|
||||||
SwitchInfo,
|
SwitchInfo,
|
||||||
SwitchState,
|
|
||||||
TextSensorInfo,
|
TextSensorInfo,
|
||||||
TextSensorState,
|
|
||||||
UserService,
|
UserService,
|
||||||
)
|
)
|
||||||
from aioesphomeapi.model import ButtonInfo
|
from aioesphomeapi.model import ButtonInfo
|
||||||
@ -56,8 +43,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
# Mapping from ESPHome info type to HA platform
|
# Mapping from ESPHome info type to HA platform
|
||||||
INFO_TYPE_TO_PLATFORM: dict[type[EntityInfo], str] = {
|
INFO_TYPE_TO_PLATFORM: dict[type[EntityInfo], str] = {
|
||||||
BinarySensorInfo: Platform.BINARY_SENSOR,
|
BinarySensorInfo: Platform.BINARY_SENSOR,
|
||||||
ButtonInfo: Platform.BINARY_SENSOR,
|
ButtonInfo: Platform.BUTTON,
|
||||||
CameraInfo: Platform.BINARY_SENSOR,
|
CameraInfo: Platform.CAMERA,
|
||||||
ClimateInfo: Platform.CLIMATE,
|
ClimateInfo: Platform.CLIMATE,
|
||||||
CoverInfo: Platform.COVER,
|
CoverInfo: Platform.COVER,
|
||||||
FanInfo: Platform.FAN,
|
FanInfo: Platform.FAN,
|
||||||
@ -71,23 +58,6 @@ INFO_TYPE_TO_PLATFORM: dict[type[EntityInfo], str] = {
|
|||||||
TextSensorInfo: Platform.SENSOR,
|
TextSensorInfo: Platform.SENSOR,
|
||||||
}
|
}
|
||||||
|
|
||||||
STATE_TYPE_TO_COMPONENT_KEY = {
|
|
||||||
BinarySensorState: Platform.BINARY_SENSOR,
|
|
||||||
EntityState: Platform.BINARY_SENSOR,
|
|
||||||
CameraState: Platform.BINARY_SENSOR,
|
|
||||||
ClimateState: Platform.CLIMATE,
|
|
||||||
CoverState: Platform.COVER,
|
|
||||||
FanState: Platform.FAN,
|
|
||||||
LightState: Platform.LIGHT,
|
|
||||||
LockState: Platform.LOCK,
|
|
||||||
MediaPlayerState: Platform.MEDIA_PLAYER,
|
|
||||||
NumberState: Platform.NUMBER,
|
|
||||||
SelectState: Platform.SELECT,
|
|
||||||
SensorState: Platform.SENSOR,
|
|
||||||
SwitchState: Platform.SWITCH,
|
|
||||||
TextSensorState: Platform.SENSOR,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RuntimeEntryData:
|
class RuntimeEntryData:
|
||||||
@ -96,7 +66,7 @@ class RuntimeEntryData:
|
|||||||
entry_id: str
|
entry_id: str
|
||||||
client: APIClient
|
client: APIClient
|
||||||
store: Store
|
store: Store
|
||||||
state: dict[str, dict[int, EntityState]] = field(default_factory=dict)
|
state: dict[type[EntityState], dict[int, EntityState]] = field(default_factory=dict)
|
||||||
info: dict[str, dict[int, EntityInfo]] = field(default_factory=dict)
|
info: dict[str, dict[int, EntityInfo]] = field(default_factory=dict)
|
||||||
|
|
||||||
# A second list of EntityInfo objects
|
# A second list of EntityInfo objects
|
||||||
@ -111,9 +81,9 @@ class RuntimeEntryData:
|
|||||||
api_version: APIVersion = field(default_factory=APIVersion)
|
api_version: APIVersion = field(default_factory=APIVersion)
|
||||||
cleanup_callbacks: list[Callable[[], None]] = field(default_factory=list)
|
cleanup_callbacks: list[Callable[[], None]] = field(default_factory=list)
|
||||||
disconnect_callbacks: list[Callable[[], None]] = field(default_factory=list)
|
disconnect_callbacks: list[Callable[[], None]] = field(default_factory=list)
|
||||||
state_subscriptions: dict[tuple[str, int], Callable[[], None]] = field(
|
state_subscriptions: dict[
|
||||||
default_factory=dict
|
tuple[type[EntityState], int], Callable[[], None]
|
||||||
)
|
] = field(default_factory=dict)
|
||||||
loaded_platforms: set[str] = field(default_factory=set)
|
loaded_platforms: set[str] = field(default_factory=set)
|
||||||
platform_load_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
|
platform_load_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
|
||||||
_storage_contents: dict[str, Any] | None = None
|
_storage_contents: dict[str, Any] | None = None
|
||||||
@ -160,24 +130,23 @@ class RuntimeEntryData:
|
|||||||
@callback
|
@callback
|
||||||
def async_subscribe_state_update(
|
def async_subscribe_state_update(
|
||||||
self,
|
self,
|
||||||
component_key: str,
|
state_type: type[EntityState],
|
||||||
state_key: int,
|
state_key: int,
|
||||||
entity_callback: Callable[[], None],
|
entity_callback: Callable[[], None],
|
||||||
) -> Callable[[], None]:
|
) -> Callable[[], None]:
|
||||||
"""Subscribe to state updates."""
|
"""Subscribe to state updates."""
|
||||||
|
|
||||||
def _unsubscribe() -> None:
|
def _unsubscribe() -> None:
|
||||||
self.state_subscriptions.pop((component_key, state_key))
|
self.state_subscriptions.pop((state_type, state_key))
|
||||||
|
|
||||||
self.state_subscriptions[(component_key, state_key)] = entity_callback
|
self.state_subscriptions[(state_type, state_key)] = entity_callback
|
||||||
return _unsubscribe
|
return _unsubscribe
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_state(self, state: EntityState) -> None:
|
def async_update_state(self, state: EntityState) -> None:
|
||||||
"""Distribute an update of state information to the target."""
|
"""Distribute an update of state information to the target."""
|
||||||
component_key = STATE_TYPE_TO_COMPONENT_KEY[type(state)]
|
subscription_key = (type(state), state.key)
|
||||||
subscription_key = (component_key, state.key)
|
self.state[type(state)][state.key] = state
|
||||||
self.state[component_key][state.key] = state
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Dispatching update with key %s: %s",
|
"Dispatching update with key %s: %s",
|
||||||
subscription_key,
|
subscription_key,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user