From 5b73bd2f8e35248cd4613d580247f97675bdbb41 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Mon, 24 Jul 2023 08:01:50 +0200 Subject: [PATCH] Use EventType for state changed [h-m] (#97117) --- .../homeassistant/triggers/state.py | 12 ++++----- .../components/homeassistant/triggers/time.py | 15 ++++++----- .../components/homekit/accessories.py | 25 +++++++++++++------ .../components/homekit/type_cameras.py | 20 +++++++++------ .../components/homekit/type_covers.py | 14 ++++++++--- .../components/homekit/type_humidifiers.py | 16 ++++++++---- .../components/integration/sensor.py | 15 ++++++----- homeassistant/components/knx/expose.py | 17 ++++++++----- .../manual_mqtt/alarm_control_panel.py | 9 ++++--- homeassistant/components/min_max/sensor.py | 18 ++++++++----- 10 files changed, 104 insertions(+), 57 deletions(-) diff --git a/homeassistant/components/homeassistant/triggers/state.py b/homeassistant/components/homeassistant/triggers/state.py index 7fc780d7976..ce2d5e64743 100644 --- a/homeassistant/components/homeassistant/triggers/state.py +++ b/homeassistant/components/homeassistant/triggers/state.py @@ -10,7 +10,6 @@ from homeassistant import exceptions from homeassistant.const import CONF_ATTRIBUTE, CONF_FOR, CONF_PLATFORM, MATCH_ALL from homeassistant.core import ( CALLBACK_TYPE, - Event, HassJob, HomeAssistant, State, @@ -22,12 +21,13 @@ from homeassistant.helpers import ( template, ) from homeassistant.helpers.event import ( + EventStateChangedData, async_track_same_state, async_track_state_change_event, process_state_match, ) from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo -from homeassistant.helpers.typing import ConfigType +from homeassistant.helpers.typing import ConfigType, EventType _LOGGER = logging.getLogger(__name__) @@ -129,11 +129,11 @@ async def async_attach_trigger( _variables = trigger_info["variables"] or {} @callback - def state_automation_listener(event: Event): + def state_automation_listener(event: EventType[EventStateChangedData]): """Listen for state changes and calls action.""" - entity: str = event.data["entity_id"] - from_s: State | None = event.data.get("old_state") - to_s: State | None = event.data.get("new_state") + entity = event.data["entity_id"] + from_s = event.data["old_state"] + to_s = event.data["new_state"] if from_s is None: old_value = None diff --git a/homeassistant/components/homeassistant/triggers/time.py b/homeassistant/components/homeassistant/triggers/time.py index a29cb5ff6da..5b3cd8590a7 100644 --- a/homeassistant/components/homeassistant/triggers/time.py +++ b/homeassistant/components/homeassistant/triggers/time.py @@ -12,15 +12,16 @@ from homeassistant.const import ( STATE_UNAVAILABLE, STATE_UNKNOWN, ) -from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback +from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, State, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers.event import ( + EventStateChangedData, async_track_point_in_time, async_track_state_change_event, async_track_time_change, ) from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo -from homeassistant.helpers.typing import ConfigType +from homeassistant.helpers.typing import ConfigType, EventType import homeassistant.util.dt as dt_util _TIME_TRIGGER_SCHEMA = vol.Any( @@ -48,7 +49,7 @@ async def async_attach_trigger( """Listen for state changes based on configuration.""" trigger_data = trigger_info["trigger_data"] entities: dict[str, CALLBACK_TYPE] = {} - removes = [] + removes: list[CALLBACK_TYPE] = [] job = HassJob(action, f"time trigger {trigger_info}") @callback @@ -68,12 +69,12 @@ async def async_attach_trigger( ) @callback - def update_entity_trigger_event(event): + def update_entity_trigger_event(event: EventType[EventStateChangedData]) -> None: """update_entity_trigger from the event.""" return update_entity_trigger(event.data["entity_id"], event.data["new_state"]) @callback - def update_entity_trigger(entity_id, new_state=None): + def update_entity_trigger(entity_id: str, new_state: State | None = None) -> None: """Update the entity trigger for the entity_id.""" # If a listener was already set up for entity, remove it. if remove := entities.pop(entity_id, None): @@ -83,6 +84,8 @@ async def async_attach_trigger( if not new_state: return + trigger_dt: datetime | None + # Check state of entity. If valid, set up a listener. if new_state.domain == "input_datetime": if has_date := new_state.attributes["has_date"]: @@ -155,7 +158,7 @@ async def async_attach_trigger( if remove: entities[entity_id] = remove - to_track = [] + to_track: list[str] = [] for at_time in config[CONF_AT]: if isinstance(at_time, str): diff --git a/homeassistant/components/homekit/accessories.py b/homeassistant/components/homekit/accessories.py index 00168ef3898..f88047795ca 100644 --- a/homeassistant/components/homekit/accessories.py +++ b/homeassistant/components/homekit/accessories.py @@ -41,13 +41,16 @@ from homeassistant.const import ( from homeassistant.core import ( CALLBACK_TYPE, Context, - Event, HomeAssistant, State, callback as ha_callback, split_entity_id, ) -from homeassistant.helpers.event import async_track_state_change_event +from homeassistant.helpers.event import ( + EventStateChangedData, + async_track_state_change_event, +) +from homeassistant.helpers.typing import EventType from homeassistant.util.decorator import Registry from .const import ( @@ -450,9 +453,11 @@ class HomeAccessory(Accessory): # type: ignore[misc] self.async_update_battery(battery_state, battery_charging_state) @ha_callback - def async_update_event_state_callback(self, event: Event) -> None: + def async_update_event_state_callback( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle state change event listener callback.""" - self.async_update_state_callback(event.data.get("new_state")) + self.async_update_state_callback(event.data["new_state"]) @ha_callback def async_update_state_callback(self, new_state: State | None) -> None: @@ -477,9 +482,11 @@ class HomeAccessory(Accessory): # type: ignore[misc] self.async_update_state(new_state) @ha_callback - def async_update_linked_battery_callback(self, event: Event) -> None: + def async_update_linked_battery_callback( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle linked battery sensor state change listener callback.""" - if (new_state := event.data.get("new_state")) is None: + if (new_state := event.data["new_state"]) is None: return if self.linked_battery_charging_sensor: battery_charging_state = None @@ -488,9 +495,11 @@ class HomeAccessory(Accessory): # type: ignore[misc] self.async_update_battery(new_state.state, battery_charging_state) @ha_callback - def async_update_linked_battery_charging_callback(self, event: Event) -> None: + def async_update_linked_battery_charging_callback( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle linked battery charging sensor state change listener callback.""" - if (new_state := event.data.get("new_state")) is None: + if (new_state := event.data["new_state"]) is None: return self.async_update_battery(None, new_state.state == STATE_ON) diff --git a/homeassistant/components/homekit/type_cameras.py b/homeassistant/components/homekit/type_cameras.py index 3bc2b1ed6ae..62d27245a1c 100644 --- a/homeassistant/components/homekit/type_cameras.py +++ b/homeassistant/components/homekit/type_cameras.py @@ -14,11 +14,13 @@ from pyhap.const import CATEGORY_CAMERA from homeassistant.components import camera from homeassistant.components.ffmpeg import get_ffmpeg_manager from homeassistant.const import STATE_ON -from homeassistant.core import Event, callback +from homeassistant.core import State, callback from homeassistant.helpers.event import ( + EventStateChangedData, async_track_state_change_event, async_track_time_interval, ) +from homeassistant.helpers.typing import EventType from .accessories import TYPES, HomeAccessory from .const import ( @@ -266,13 +268,15 @@ class Camera(HomeAccessory, PyhapCamera): await super().run() @callback - def _async_update_motion_state_event(self, event: Event) -> None: + def _async_update_motion_state_event( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle state change event listener callback.""" if not state_changed_event_is_same_state(event): - self._async_update_motion_state(event.data.get("new_state")) + self._async_update_motion_state(event.data["new_state"]) @callback - def _async_update_motion_state(self, new_state): + def _async_update_motion_state(self, new_state: State | None) -> None: """Handle link motion sensor state change to update HomeKit value.""" if not new_state: return @@ -290,13 +294,15 @@ class Camera(HomeAccessory, PyhapCamera): ) @callback - def _async_update_doorbell_state_event(self, event: Event) -> None: + def _async_update_doorbell_state_event( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle state change event listener callback.""" if not state_changed_event_is_same_state(event): - self._async_update_doorbell_state(event.data.get("new_state")) + self._async_update_doorbell_state(event.data["new_state"]) @callback - def _async_update_doorbell_state(self, new_state): + def _async_update_doorbell_state(self, new_state: State | None) -> None: """Handle link doorbell sensor state change to update HomeKit value.""" if not new_state: return diff --git a/homeassistant/components/homekit/type_covers.py b/homeassistant/components/homekit/type_covers.py index 05feb580572..ea0a5054ffd 100644 --- a/homeassistant/components/homekit/type_covers.py +++ b/homeassistant/components/homekit/type_covers.py @@ -31,7 +31,11 @@ from homeassistant.const import ( STATE_OPENING, ) from homeassistant.core import State, callback -from homeassistant.helpers.event import async_track_state_change_event +from homeassistant.helpers.event import ( + EventStateChangedData, + async_track_state_change_event, +) +from homeassistant.helpers.typing import EventType from .accessories import TYPES, HomeAccessory from .const import ( @@ -135,12 +139,14 @@ class GarageDoorOpener(HomeAccessory): await super().run() @callback - def _async_update_obstruction_event(self, event): + def _async_update_obstruction_event( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle state change event listener callback.""" - self._async_update_obstruction_state(event.data.get("new_state")) + self._async_update_obstruction_state(event.data["new_state"]) @callback - def _async_update_obstruction_state(self, new_state): + def _async_update_obstruction_state(self, new_state: State | None) -> None: """Handle linked obstruction sensor state change to update HomeKit value.""" if not new_state: return diff --git a/homeassistant/components/homekit/type_humidifiers.py b/homeassistant/components/homekit/type_humidifiers.py index 33c35908cd1..f9f572a096c 100644 --- a/homeassistant/components/homekit/type_humidifiers.py +++ b/homeassistant/components/homekit/type_humidifiers.py @@ -21,8 +21,12 @@ from homeassistant.const import ( SERVICE_TURN_ON, STATE_ON, ) -from homeassistant.core import callback -from homeassistant.helpers.event import async_track_state_change_event +from homeassistant.core import State, callback +from homeassistant.helpers.event import ( + EventStateChangedData, + async_track_state_change_event, +) +from homeassistant.helpers.typing import EventType from .accessories import TYPES, HomeAccessory from .const import ( @@ -157,12 +161,14 @@ class HumidifierDehumidifier(HomeAccessory): await super().run() @callback - def async_update_current_humidity_event(self, event): + def async_update_current_humidity_event( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle state change event listener callback.""" - self._async_update_current_humidity(event.data.get("new_state")) + self._async_update_current_humidity(event.data["new_state"]) @callback - def _async_update_current_humidity(self, new_state): + def _async_update_current_humidity(self, new_state: State | None) -> None: """Handle linked humidity sensor state change to update HomeKit value.""" if new_state is None: _LOGGER.error( diff --git a/homeassistant/components/integration/sensor.py b/homeassistant/components/integration/sensor.py index e4ae3cde883..5ce64de9b33 100644 --- a/homeassistant/components/integration/sensor.py +++ b/homeassistant/components/integration/sensor.py @@ -26,7 +26,7 @@ from homeassistant.const import ( STATE_UNKNOWN, UnitOfTime, ) -from homeassistant.core import Event, HomeAssistant, State, callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import ( config_validation as cv, device_registry as dr, @@ -34,8 +34,11 @@ from homeassistant.helpers import ( ) from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.event import async_track_state_change_event -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.event import ( + EventStateChangedData, + async_track_state_change_event, +) +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, EventType from .const import ( CONF_ROUND_DIGITS, @@ -290,10 +293,10 @@ class IntegrationSensor(RestoreSensor): self._unit_of_measurement = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) @callback - def calc_integration(event: Event) -> None: + def calc_integration(event: EventType[EventStateChangedData]) -> None: """Handle the sensor state changes.""" - old_state: State | None = event.data.get("old_state") - new_state: State | None = event.data.get("new_state") + old_state = event.data["old_state"] + new_state = event.data["new_state"] # We may want to update our state before an early return, # based on the source sensor's unit_of_measurement diff --git a/homeassistant/components/knx/expose.py b/homeassistant/components/knx/expose.py index 308fc4eacd1..e14ee501d7b 100644 --- a/homeassistant/components/knx/expose.py +++ b/homeassistant/components/knx/expose.py @@ -17,9 +17,12 @@ from homeassistant.const import ( STATE_UNAVAILABLE, STATE_UNKNOWN, ) -from homeassistant.core import Event, HomeAssistant, State, callback -from homeassistant.helpers.event import async_track_state_change_event -from homeassistant.helpers.typing import ConfigType, StateType +from homeassistant.core import HomeAssistant, State, callback +from homeassistant.helpers.event import ( + EventStateChangedData, + async_track_state_change_event, +) +from homeassistant.helpers.typing import ConfigType, EventType, StateType from .const import CONF_RESPOND_TO_READ, KNX_ADDRESS from .schema import ExposeSchema @@ -145,12 +148,14 @@ class KNXExposeSensor: return str(value)[:14] return value - async def _async_entity_changed(self, event: Event) -> None: + async def _async_entity_changed( + self, event: EventType[EventStateChangedData] + ) -> None: """Handle entity change.""" - new_state = event.data.get("new_state") + new_state = event.data["new_state"] if (new_value := self._get_expose_value(new_state)) is None: return - old_state = event.data.get("old_state") + old_state = event.data["old_state"] # don't use default value for comparison on first state change (old_state is None) old_value = self._get_expose_value(old_state) if old_state is not None else None # don't send same value sequentially diff --git a/homeassistant/components/manual_mqtt/alarm_control_panel.py b/homeassistant/components/manual_mqtt/alarm_control_panel.py index adb251bd71a..69cd1ef3d11 100644 --- a/homeassistant/components/manual_mqtt/alarm_control_panel.py +++ b/homeassistant/components/manual_mqtt/alarm_control_panel.py @@ -33,10 +33,11 @@ from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import ( + EventStateChangedData, async_track_point_in_time, async_track_state_change_event, ) -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, EventType import homeassistant.util.dt as dt_util _LOGGER = logging.getLogger(__name__) @@ -481,9 +482,11 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity): self.hass, self._command_topic, message_received, self._qos ) - async def _async_state_changed_listener(self, event): + async def _async_state_changed_listener( + self, event: EventType[EventStateChangedData] + ) -> None: """Publish state change to MQTT.""" - if (new_state := event.data.get("new_state")) is None: + if (new_state := event.data["new_state"]) is None: return await mqtt.async_publish( self.hass, self._state_topic, new_state.state, self._qos, True diff --git a/homeassistant/components/min_max/sensor.py b/homeassistant/components/min_max/sensor.py index d1ea9695322..cc26a684a8d 100644 --- a/homeassistant/components/min_max/sensor.py +++ b/homeassistant/components/min_max/sensor.py @@ -22,14 +22,18 @@ from homeassistant.const import ( STATE_UNAVAILABLE, STATE_UNKNOWN, ) -from homeassistant.core import Event, HomeAssistant, State, callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv, entity_registry as er from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.event import async_track_state_change_event +from homeassistant.helpers.event import ( + EventStateChangedData, + async_track_state_change_event, +) from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.helpers.typing import ( ConfigType, DiscoveryInfoType, + EventType, StateType, ) @@ -253,7 +257,9 @@ class MinMaxSensor(SensorEntity): # Replay current state of source entities for entity_id in self._entity_ids: state = self.hass.states.get(entity_id) - state_event = Event("", {"entity_id": entity_id, "new_state": state}) + state_event: EventType[EventStateChangedData] = EventType( + "", {"entity_id": entity_id, "new_state": state, "old_state": None} + ) self._async_min_max_sensor_state_listener(state_event, update_state=False) self._calc_values() @@ -286,11 +292,11 @@ class MinMaxSensor(SensorEntity): @callback def _async_min_max_sensor_state_listener( - self, event: Event, update_state: bool = True + self, event: EventType[EventStateChangedData], update_state: bool = True ) -> None: """Handle the sensor state changes.""" - new_state: State | None = event.data.get("new_state") - entity: str = event.data["entity_id"] + new_state = event.data["new_state"] + entity = event.data["entity_id"] if ( new_state is None