diff --git a/homeassistant/components/homee/__init__.py b/homeassistant/components/homee/__init__.py index 654bdde6211..83705d4fed1 100644 --- a/homeassistant/components/homee/__init__.py +++ b/homeassistant/components/homee/__init__.py @@ -20,6 +20,7 @@ PLATFORMS = [ Platform.BUTTON, Platform.CLIMATE, Platform.COVER, + Platform.EVENT, Platform.FAN, Platform.LIGHT, Platform.LOCK, diff --git a/homeassistant/components/homee/event.py b/homeassistant/components/homee/event.py new file mode 100644 index 00000000000..047d9e2e122 --- /dev/null +++ b/homeassistant/components/homee/event.py @@ -0,0 +1,61 @@ +"""The homee event platform.""" + +from pyHomee.const import AttributeType +from pyHomee.model import HomeeAttribute + +from homeassistant.components.event import EventDeviceClass, EventEntity +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import HomeeConfigEntry +from .entity import HomeeEntity + +PARALLEL_UPDATES = 0 + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: HomeeConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Add event entities for homee.""" + + async_add_entities( + HomeeEvent(attribute, config_entry) + for node in config_entry.runtime_data.nodes + for attribute in node.attributes + if attribute.type == AttributeType.UP_DOWN_REMOTE + ) + + +class HomeeEvent(HomeeEntity, EventEntity): + """Representation of a homee event.""" + + _attr_translation_key = "up_down_remote" + _attr_event_types = [ + "released", + "up", + "down", + "stop", + "up_long", + "down_long", + "stop_long", + "c_button", + "b_button", + "a_button", + ] + _attr_device_class = EventDeviceClass.BUTTON + + async def async_added_to_hass(self) -> None: + """Add the homee event entity to home assistant.""" + await super().async_added_to_hass() + self.async_on_remove( + self._attribute.add_on_changed_listener(self._event_triggered) + ) + + @callback + def _event_triggered(self, event: HomeeAttribute) -> None: + """Handle a homee event.""" + if event.type == AttributeType.UP_DOWN_REMOTE: + self._trigger_event(self.event_types[int(event.current_value)]) + self.schedule_update_ha_state() diff --git a/homeassistant/components/homee/strings.json b/homeassistant/components/homee/strings.json index 092fca0c0ac..5e124aa427e 100644 --- a/homeassistant/components/homee/strings.json +++ b/homeassistant/components/homee/strings.json @@ -147,6 +147,27 @@ } } }, + "event": { + "up_down_remote": { + "name": "Up/down remote", + "state_attributes": { + "event_type": { + "state": { + "release": "Released", + "up": "Up", + "down": "Down", + "stop": "Stop", + "up_long": "Up (long press)", + "down_long": "Down (long press)", + "stop_long": "Stop (long press)", + "c_button": "C button", + "b_button": "B button", + "a_button": "A button" + } + } + } + } + }, "fan": { "homee": { "state_attributes": { diff --git a/tests/components/homee/fixtures/events.json b/tests/components/homee/fixtures/events.json new file mode 100644 index 00000000000..351d35ec497 --- /dev/null +++ b/tests/components/homee/fixtures/events.json @@ -0,0 +1,46 @@ +{ + "id": 1, + "name": "Remote Control", + "profile": 41, + "image": "default", + "favorite": 0, + "order": 29, + "protocol": 23, + "routing": 0, + "state": 1, + "state_changed": 1715356788, + "added": 1615396304, + "history": 1, + "cube_type": 14, + "note": "", + "services": 0, + "phonetic_name": "", + "owner": 2, + "security": 0, + "attributes": [ + { + "id": 1, + "node_id": 1, + "instance": 0, + "minimum": 0, + "maximum": 9, + "current_value": 0.0, + "target_value": 0.0, + "last_value": 2.0, + "unit": "n/a", + "step_value": 1.0, + "editable": 0, + "type": 300, + "state": 1, + "last_changed": 1713470190, + "changed_by": 1, + "changed_by_id": 0, + "based_on": 1, + "data": "", + "name": "", + "options": { + "observed_by": [145] + } + } + ] +} diff --git a/tests/components/homee/snapshots/test_event.ambr b/tests/components/homee/snapshots/test_event.ambr new file mode 100644 index 00000000000..45194526ef0 --- /dev/null +++ b/tests/components/homee/snapshots/test_event.ambr @@ -0,0 +1,75 @@ +# serializer version: 1 +# name: test_event_snapshot[event.remote_control_up_down_remote-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'event_types': list([ + 'released', + 'up', + 'down', + 'stop', + 'up_long', + 'down_long', + 'stop_long', + 'c_button', + 'b_button', + 'a_button', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'event', + 'entity_category': None, + 'entity_id': 'event.remote_control_up_down_remote', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Up/down remote', + 'platform': 'homee', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'up_down_remote', + 'unique_id': '00055511EECC-1-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_event_snapshot[event.remote_control_up_down_remote-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'button', + 'event_type': None, + 'event_types': list([ + 'released', + 'up', + 'down', + 'stop', + 'up_long', + 'down_long', + 'stop_long', + 'c_button', + 'b_button', + 'a_button', + ]), + 'friendly_name': 'Remote Control Up/down remote', + }), + 'context': , + 'entity_id': 'event.remote_control_up_down_remote', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- diff --git a/tests/components/homee/test_event.py b/tests/components/homee/test_event.py new file mode 100644 index 00000000000..0ffa7cd8530 --- /dev/null +++ b/tests/components/homee/test_event.py @@ -0,0 +1,65 @@ +"""Test homee events.""" + +from unittest.mock import MagicMock, patch + +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.event import ATTR_EVENT_TYPE +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import build_mock_node, setup_integration + +from tests.common import MockConfigEntry, snapshot_platform + + +async def test_event_fires( + hass: HomeAssistant, + mock_homee: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test that the correct event fires when the attribute changes.""" + + EVENT_TYPES = [ + "released", + "up", + "down", + "stop", + "up_long", + "down_long", + "stop_long", + "c_button", + "b_button", + "a_button", + ] + mock_homee.nodes = [build_mock_node("events.json")] + mock_homee.get_node_by_id.return_value = mock_homee.nodes[0] + await setup_integration(hass, mock_config_entry) + + # Simulate the event triggers. + attribute = mock_homee.nodes[0].attributes[0] + for i, event_type in enumerate(EVENT_TYPES): + attribute.current_value = i + attribute.add_on_changed_listener.call_args_list[1][0][0](attribute) + await hass.async_block_till_done() + + # Check if the event was fired + state = hass.states.get("event.remote_control_up_down_remote") + assert state.attributes[ATTR_EVENT_TYPE] == event_type + + +async def test_event_snapshot( + hass: HomeAssistant, + mock_homee: MagicMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test the event entity snapshot.""" + with patch("homeassistant.components.homee.PLATFORMS", [Platform.EVENT]): + mock_homee.nodes = [build_mock_node("events.json")] + mock_homee.get_node_by_id.return_value = mock_homee.nodes[0] + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)