diff --git a/homeassistant/components/esphome/entry_data.py b/homeassistant/components/esphome/entry_data.py index a840fc3a17e..7316c09cc5e 100644 --- a/homeassistant/components/esphome/entry_data.py +++ b/homeassistant/components/esphome/entry_data.py @@ -24,6 +24,8 @@ from aioesphomeapi import ( DeviceInfo, EntityInfo, EntityState, + Event, + EventInfo, FanInfo, LightInfo, LockInfo, @@ -70,6 +72,7 @@ INFO_TYPE_TO_PLATFORM: dict[type[EntityInfo], Platform] = { CoverInfo: Platform.COVER, DateInfo: Platform.DATE, DateTimeInfo: Platform.DATETIME, + EventInfo: Platform.EVENT, FanInfo: Platform.FAN, LightInfo: Platform.LIGHT, LockInfo: Platform.LOCK, @@ -345,7 +348,7 @@ class RuntimeEntryData: if ( current_state == state and subscription_key not in stale_state - and state_type is not CameraState + and state_type not in (CameraState, Event) and not ( state_type is SensorState and (platform_info := self.info.get(SensorInfo)) diff --git a/homeassistant/components/esphome/event.py b/homeassistant/components/esphome/event.py new file mode 100644 index 00000000000..3c7331beba0 --- /dev/null +++ b/homeassistant/components/esphome/event.py @@ -0,0 +1,48 @@ +"""Support for ESPHome event components.""" + +from __future__ import annotations + +from aioesphomeapi import EntityInfo, Event, EventInfo + +from homeassistant.components.event import EventDeviceClass, EventEntity +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.util.enum import try_parse_enum + +from .entity import EsphomeEntity, platform_async_setup_entry + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up ESPHome event based on a config entry.""" + await platform_async_setup_entry( + hass, + entry, + async_add_entities, + info_type=EventInfo, + entity_type=EsphomeEvent, + state_type=Event, + ) + + +class EsphomeEvent(EsphomeEntity[EventInfo, Event], EventEntity): + """An event implementation for ESPHome.""" + + @callback + def _on_static_info_update(self, static_info: EntityInfo) -> None: + """Set attrs from static info.""" + super()._on_static_info_update(static_info) + static_info = self._static_info + if event_types := static_info.event_types: + self._attr_event_types = event_types + self._attr_device_class = try_parse_enum( + EventDeviceClass, static_info.device_class + ) + + @callback + def _on_state_update(self) -> None: + self._update_state_from_entry_data() + self._trigger_event(self._state.event_type) + self.async_write_ha_state() diff --git a/tests/components/esphome/test_event.py b/tests/components/esphome/test_event.py new file mode 100644 index 00000000000..c17dc4d98a9 --- /dev/null +++ b/tests/components/esphome/test_event.py @@ -0,0 +1,38 @@ +"""Test ESPHome Events.""" + +from aioesphomeapi import APIClient, Event, EventInfo +import pytest + +from homeassistant.components.event import EventDeviceClass +from homeassistant.core import HomeAssistant + + +@pytest.mark.freeze_time("2024-04-24 00:00:00+00:00") +async def test_generic_event_entity( + hass: HomeAssistant, + mock_client: APIClient, + mock_generic_device_entry, +) -> None: + """Test a generic event entity.""" + entity_info = [ + EventInfo( + object_id="myevent", + key=1, + name="my event", + unique_id="my_event", + event_types=["type1", "type2"], + device_class=EventDeviceClass.BUTTON, + ) + ] + states = [Event(key=1, event_type="type1")] + user_service = [] + await mock_generic_device_entry( + mock_client=mock_client, + entity_info=entity_info, + user_service=user_service, + states=states, + ) + state = hass.states.get("event.test_myevent") + assert state is not None + assert state.state == "2024-04-24T00:00:00.000+00:00" + assert state.attributes["event_type"] == "type1"