1
0
mirror of https://github.com/home-assistant/core synced 2024-07-08 20:17:01 +00:00

Add async_track_state_reported_event to fix integration performance regression (#120622)

split from https://github.com/home-assistant/core/pull/120621
This commit is contained in:
J. Nick Koston 2024-06-26 22:04:27 -05:00 committed by GitHub
parent f189d87fe9
commit a5a631148e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 7 deletions

View File

@ -17,6 +17,7 @@ from typing import TYPE_CHECKING, Any, Concatenate, Generic, TypeVar
from homeassistant.const import (
EVENT_CORE_CONFIG_UPDATE,
EVENT_STATE_CHANGED,
EVENT_STATE_REPORTED,
MATCH_ALL,
SUN_EVENT_SUNRISE,
SUN_EVENT_SUNSET,
@ -26,6 +27,7 @@ from homeassistant.core import (
Event,
# Explicit reexport of 'EventStateChangedData' for backwards compatibility
EventStateChangedData as EventStateChangedData, # noqa: PLC0414
EventStateReportedData,
HassJob,
HassJobType,
HomeAssistant,
@ -57,6 +59,9 @@ from .typing import TemplateVarsType
_TRACK_STATE_CHANGE_DATA: HassKey[_KeyedEventData[EventStateChangedData]] = HassKey(
"track_state_change_data"
)
_TRACK_STATE_REPORTED_DATA: HassKey[_KeyedEventData[EventStateReportedData]] = HassKey(
"track_state_reported_data"
)
_TRACK_STATE_ADDED_DOMAIN_DATA: HassKey[_KeyedEventData[EventStateChangedData]] = (
HassKey("track_state_added_domain_data")
)
@ -324,8 +329,8 @@ def async_track_state_change_event(
@callback
def _async_dispatch_entity_id_event(
hass: HomeAssistant,
callbacks: dict[str, list[HassJob[[Event[EventStateChangedData]], Any]]],
event: Event[EventStateChangedData],
callbacks: dict[str, list[HassJob[[Event[_TypedDictT]], Any]]],
event: Event[_TypedDictT],
) -> None:
"""Dispatch to listeners."""
if not (callbacks_list := callbacks.get(event.data["entity_id"])):
@ -342,10 +347,10 @@ def _async_dispatch_entity_id_event(
@callback
def _async_state_change_filter(
def _async_state_filter(
hass: HomeAssistant,
callbacks: dict[str, list[HassJob[[Event[EventStateChangedData]], Any]]],
event_data: EventStateChangedData,
callbacks: dict[str, list[HassJob[[Event[_TypedDictT]], Any]]],
event_data: _TypedDictT,
) -> bool:
"""Filter state changes by entity_id."""
return event_data["entity_id"] in callbacks
@ -355,7 +360,7 @@ _KEYED_TRACK_STATE_CHANGE = _KeyedEventTracker(
key=_TRACK_STATE_CHANGE_DATA,
event_type=EVENT_STATE_CHANGED,
dispatcher_callable=_async_dispatch_entity_id_event,
filter_callable=_async_state_change_filter,
filter_callable=_async_state_filter,
)
@ -372,6 +377,26 @@ def _async_track_state_change_event(
)
_KEYED_TRACK_STATE_REPORTED = _KeyedEventTracker(
key=_TRACK_STATE_REPORTED_DATA,
event_type=EVENT_STATE_REPORTED,
dispatcher_callable=_async_dispatch_entity_id_event,
filter_callable=_async_state_filter,
)
def async_track_state_reported_event(
hass: HomeAssistant,
entity_ids: str | Iterable[str],
action: Callable[[Event[EventStateReportedData]], Any],
job_type: HassJobType | None = None,
) -> CALLBACK_TYPE:
"""Track EVENT_STATE_REPORTED by entity_id without lowercasing."""
return _async_track_event(
_KEYED_TRACK_STATE_REPORTED, hass, entity_ids, action, job_type
)
@callback
def _remove_empty_listener() -> None:
"""Remove a listener that does nothing."""

View File

@ -15,7 +15,13 @@ import pytest
from homeassistant.const import MATCH_ALL
import homeassistant.core as ha
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, callback
from homeassistant.core import (
Event,
EventStateChangedData,
EventStateReportedData,
HomeAssistant,
callback,
)
from homeassistant.exceptions import TemplateError
from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
@ -34,6 +40,7 @@ from homeassistant.helpers.event import (
async_track_state_change_event,
async_track_state_change_filtered,
async_track_state_removed_domain,
async_track_state_reported_event,
async_track_sunrise,
async_track_sunset,
async_track_template,
@ -4907,3 +4914,26 @@ async def test_track_point_in_time_repr(
assert "Exception in callback _TrackPointUTCTime" in caplog.text
assert "._raise_exception" in caplog.text
await hass.async_block_till_done(wait_background_tasks=True)
async def test_async_track_state_reported_event(hass: HomeAssistant) -> None:
"""Test async_track_state_reported_event."""
tracker_called: list[ha.State] = []
@ha.callback
def single_run_callback(event: Event[EventStateReportedData]) -> None:
new_state = event.data["new_state"]
tracker_called.append(new_state)
unsub = async_track_state_reported_event(
hass, ["light.bowl", "light.top"], single_run_callback
)
hass.states.async_set("light.bowl", "on")
hass.states.async_set("light.top", "on")
await hass.async_block_till_done()
assert len(tracker_called) == 0
hass.states.async_set("light.bowl", "on")
hass.states.async_set("light.top", "on")
await hass.async_block_till_done()
assert len(tracker_called) == 2
unsub()