From 1a772b6df206741ff197e3f5091bcd72f45bce24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=ADlio=20Costa?= Date: Wed, 25 Mar 2026 05:53:16 +0000 Subject: [PATCH] Add button platform to LG Infrared (#166375) --- .../components/lg_infrared/__init__.py | 2 +- .../components/lg_infrared/button.py | 147 ++ .../components/lg_infrared/strings.json | 88 ++ tests/components/lg_infrared/conftest.py | 3 +- .../lg_infrared/snapshots/test_button.ambr | 1401 +++++++++++++++++ tests/components/lg_infrared/test_button.py | 107 ++ .../lg_infrared/test_media_player.py | 26 +- tests/components/lg_infrared/utils.py | 33 + 8 files changed, 1783 insertions(+), 24 deletions(-) create mode 100644 homeassistant/components/lg_infrared/button.py create mode 100644 tests/components/lg_infrared/snapshots/test_button.ambr create mode 100644 tests/components/lg_infrared/test_button.py create mode 100644 tests/components/lg_infrared/utils.py diff --git a/homeassistant/components/lg_infrared/__init__.py b/homeassistant/components/lg_infrared/__init__.py index 16d6a2ce7da..d8b6e51d239 100644 --- a/homeassistant/components/lg_infrared/__init__.py +++ b/homeassistant/components/lg_infrared/__init__.py @@ -6,7 +6,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant -PLATFORMS = [Platform.MEDIA_PLAYER] +PLATFORMS = [Platform.BUTTON, Platform.MEDIA_PLAYER] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/lg_infrared/button.py b/homeassistant/components/lg_infrared/button.py new file mode 100644 index 00000000000..9c1482205e4 --- /dev/null +++ b/homeassistant/components/lg_infrared/button.py @@ -0,0 +1,147 @@ +"""Button platform for LG IR integration.""" + +from __future__ import annotations + +from dataclasses import dataclass + +from infrared_protocols.codes.lg.tv import LGTVCode + +from homeassistant.components.button import ButtonEntity, ButtonEntityDescription +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from .const import CONF_DEVICE_TYPE, CONF_INFRARED_ENTITY_ID, LGDeviceType +from .entity import LgIrEntity + +PARALLEL_UPDATES = 1 + + +@dataclass(frozen=True, kw_only=True) +class LgIrButtonEntityDescription(ButtonEntityDescription): + """Describes LG IR button entity.""" + + command_code: LGTVCode + + +TV_BUTTON_DESCRIPTIONS: tuple[LgIrButtonEntityDescription, ...] = ( + LgIrButtonEntityDescription( + key="power_on", translation_key="power_on", command_code=LGTVCode.POWER_ON + ), + LgIrButtonEntityDescription( + key="power_off", translation_key="power_off", command_code=LGTVCode.POWER_OFF + ), + LgIrButtonEntityDescription( + key="hdmi_1", translation_key="hdmi_1", command_code=LGTVCode.HDMI_1 + ), + LgIrButtonEntityDescription( + key="hdmi_2", translation_key="hdmi_2", command_code=LGTVCode.HDMI_2 + ), + LgIrButtonEntityDescription( + key="hdmi_3", translation_key="hdmi_3", command_code=LGTVCode.HDMI_3 + ), + LgIrButtonEntityDescription( + key="hdmi_4", translation_key="hdmi_4", command_code=LGTVCode.HDMI_4 + ), + LgIrButtonEntityDescription( + key="exit", translation_key="exit", command_code=LGTVCode.EXIT + ), + LgIrButtonEntityDescription( + key="info", translation_key="info", command_code=LGTVCode.INFO + ), + LgIrButtonEntityDescription( + key="guide", translation_key="guide", command_code=LGTVCode.GUIDE + ), + LgIrButtonEntityDescription( + key="up", translation_key="up", command_code=LGTVCode.NAV_UP + ), + LgIrButtonEntityDescription( + key="down", translation_key="down", command_code=LGTVCode.NAV_DOWN + ), + LgIrButtonEntityDescription( + key="left", translation_key="left", command_code=LGTVCode.NAV_LEFT + ), + LgIrButtonEntityDescription( + key="right", translation_key="right", command_code=LGTVCode.NAV_RIGHT + ), + LgIrButtonEntityDescription( + key="ok", translation_key="ok", command_code=LGTVCode.OK + ), + LgIrButtonEntityDescription( + key="back", translation_key="back", command_code=LGTVCode.BACK + ), + LgIrButtonEntityDescription( + key="home", translation_key="home", command_code=LGTVCode.HOME + ), + LgIrButtonEntityDescription( + key="menu", translation_key="menu", command_code=LGTVCode.MENU + ), + LgIrButtonEntityDescription( + key="input", translation_key="input", command_code=LGTVCode.INPUT + ), + LgIrButtonEntityDescription( + key="num_0", translation_key="num_0", command_code=LGTVCode.NUM_0 + ), + LgIrButtonEntityDescription( + key="num_1", translation_key="num_1", command_code=LGTVCode.NUM_1 + ), + LgIrButtonEntityDescription( + key="num_2", translation_key="num_2", command_code=LGTVCode.NUM_2 + ), + LgIrButtonEntityDescription( + key="num_3", translation_key="num_3", command_code=LGTVCode.NUM_3 + ), + LgIrButtonEntityDescription( + key="num_4", translation_key="num_4", command_code=LGTVCode.NUM_4 + ), + LgIrButtonEntityDescription( + key="num_5", translation_key="num_5", command_code=LGTVCode.NUM_5 + ), + LgIrButtonEntityDescription( + key="num_6", translation_key="num_6", command_code=LGTVCode.NUM_6 + ), + LgIrButtonEntityDescription( + key="num_7", translation_key="num_7", command_code=LGTVCode.NUM_7 + ), + LgIrButtonEntityDescription( + key="num_8", translation_key="num_8", command_code=LGTVCode.NUM_8 + ), + LgIrButtonEntityDescription( + key="num_9", translation_key="num_9", command_code=LGTVCode.NUM_9 + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up LG IR buttons from config entry.""" + infrared_entity_id = entry.data[CONF_INFRARED_ENTITY_ID] + device_type = entry.data[CONF_DEVICE_TYPE] + if device_type == LGDeviceType.TV: + async_add_entities( + LgIrButton(entry, infrared_entity_id, description) + for description in TV_BUTTON_DESCRIPTIONS + ) + + +class LgIrButton(LgIrEntity, ButtonEntity): + """LG IR button entity.""" + + entity_description: LgIrButtonEntityDescription + + def __init__( + self, + entry: ConfigEntry, + infrared_entity_id: str, + description: LgIrButtonEntityDescription, + ) -> None: + """Initialize LG IR button.""" + super().__init__(entry, infrared_entity_id, unique_id_suffix=description.key) + self.entity_description = description + + async def async_press(self) -> None: + """Press the button.""" + await self._send_command(self.entity_description.command_code) diff --git a/homeassistant/components/lg_infrared/strings.json b/homeassistant/components/lg_infrared/strings.json index 67d6e04bf0f..0c81b3ea0f5 100644 --- a/homeassistant/components/lg_infrared/strings.json +++ b/homeassistant/components/lg_infrared/strings.json @@ -19,6 +19,94 @@ } } }, + "entity": { + "button": { + "back": { + "name": "Back" + }, + "down": { + "name": "Down" + }, + "exit": { + "name": "Exit" + }, + "guide": { + "name": "Guide" + }, + "hdmi_1": { + "name": "HDMI 1" + }, + "hdmi_2": { + "name": "HDMI 2" + }, + "hdmi_3": { + "name": "HDMI 3" + }, + "hdmi_4": { + "name": "HDMI 4" + }, + "home": { + "name": "Home" + }, + "info": { + "name": "Info" + }, + "input": { + "name": "Input" + }, + "left": { + "name": "Left" + }, + "menu": { + "name": "Menu" + }, + "num_0": { + "name": "Number 0" + }, + "num_1": { + "name": "Number 1" + }, + "num_2": { + "name": "Number 2" + }, + "num_3": { + "name": "Number 3" + }, + "num_4": { + "name": "Number 4" + }, + "num_5": { + "name": "Number 5" + }, + "num_6": { + "name": "Number 6" + }, + "num_7": { + "name": "Number 7" + }, + "num_8": { + "name": "Number 8" + }, + "num_9": { + "name": "Number 9" + }, + "ok": { + "name": "OK" + }, + "power_off": { + "name": "Power off" + }, + "power_on": { + "name": "Power on" + }, + "right": { + "name": "Right" + }, + "up": { + "name": "Up" + } + } + }, "selector": { "device_type": { "options": { diff --git a/tests/components/lg_infrared/conftest.py b/tests/components/lg_infrared/conftest.py index 59e409560fc..ffb68fb35d4 100644 --- a/tests/components/lg_infrared/conftest.py +++ b/tests/components/lg_infrared/conftest.py @@ -13,6 +13,7 @@ from homeassistant.components.infrared import ( DOMAIN as INFRARED_DOMAIN, InfraredEntity, ) +from homeassistant.components.lg_infrared import PLATFORMS from homeassistant.components.lg_infrared.const import ( CONF_DEVICE_TYPE, CONF_INFRARED_ENTITY_ID, @@ -68,7 +69,7 @@ def mock_infrared_entity() -> MockInfraredEntity: @pytest.fixture def platforms() -> list[Platform]: """Return platforms to set up.""" - return [Platform.MEDIA_PLAYER] + return PLATFORMS @pytest.fixture diff --git a/tests/components/lg_infrared/snapshots/test_button.ambr b/tests/components/lg_infrared/snapshots/test_button.ambr new file mode 100644 index 00000000000..2bc030849bf --- /dev/null +++ b/tests/components/lg_infrared/snapshots/test_button.ambr @@ -0,0 +1,1401 @@ +# serializer version: 1 +# name: test_entities[button.lg_tv_back-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_back', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Back', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Back', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'back', + 'unique_id': '01JTEST0000000000000000000_back', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_back-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Back', + }), + 'context': , + 'entity_id': 'button.lg_tv_back', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_down-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_down', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Down', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Down', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'down', + 'unique_id': '01JTEST0000000000000000000_down', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_down-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Down', + }), + 'context': , + 'entity_id': 'button.lg_tv_down', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_exit-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_exit', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Exit', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Exit', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'exit', + 'unique_id': '01JTEST0000000000000000000_exit', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_exit-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Exit', + }), + 'context': , + 'entity_id': 'button.lg_tv_exit', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_guide-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_guide', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Guide', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Guide', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'guide', + 'unique_id': '01JTEST0000000000000000000_guide', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_guide-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Guide', + }), + 'context': , + 'entity_id': 'button.lg_tv_guide', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_hdmi_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_hdmi_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'HDMI 1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'HDMI 1', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'hdmi_1', + 'unique_id': '01JTEST0000000000000000000_hdmi_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_hdmi_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV HDMI 1', + }), + 'context': , + 'entity_id': 'button.lg_tv_hdmi_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_hdmi_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_hdmi_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'HDMI 2', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'HDMI 2', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'hdmi_2', + 'unique_id': '01JTEST0000000000000000000_hdmi_2', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_hdmi_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV HDMI 2', + }), + 'context': , + 'entity_id': 'button.lg_tv_hdmi_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_hdmi_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_hdmi_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'HDMI 3', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'HDMI 3', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'hdmi_3', + 'unique_id': '01JTEST0000000000000000000_hdmi_3', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_hdmi_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV HDMI 3', + }), + 'context': , + 'entity_id': 'button.lg_tv_hdmi_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_hdmi_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_hdmi_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'HDMI 4', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'HDMI 4', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'hdmi_4', + 'unique_id': '01JTEST0000000000000000000_hdmi_4', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_hdmi_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV HDMI 4', + }), + 'context': , + 'entity_id': 'button.lg_tv_hdmi_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_home-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_home', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Home', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Home', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'home', + 'unique_id': '01JTEST0000000000000000000_home', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_home-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Home', + }), + 'context': , + 'entity_id': 'button.lg_tv_home', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_info-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_info', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Info', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Info', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'info', + 'unique_id': '01JTEST0000000000000000000_info', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_info-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Info', + }), + 'context': , + 'entity_id': 'button.lg_tv_info', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_input-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_input', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Input', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Input', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'input', + 'unique_id': '01JTEST0000000000000000000_input', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_input-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Input', + }), + 'context': , + 'entity_id': 'button.lg_tv_input', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_left-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_left', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Left', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Left', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'left', + 'unique_id': '01JTEST0000000000000000000_left', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_left-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Left', + }), + 'context': , + 'entity_id': 'button.lg_tv_left', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_menu-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_menu', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Menu', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Menu', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'menu', + 'unique_id': '01JTEST0000000000000000000_menu', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_menu-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Menu', + }), + 'context': , + 'entity_id': 'button.lg_tv_menu', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_0-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_0', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 0', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 0', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_0', + 'unique_id': '01JTEST0000000000000000000_num_0', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_0-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 0', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_0', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 1', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_1', + 'unique_id': '01JTEST0000000000000000000_num_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 1', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 2', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 2', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_2', + 'unique_id': '01JTEST0000000000000000000_num_2', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 2', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 3', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 3', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_3', + 'unique_id': '01JTEST0000000000000000000_num_3', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 3', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 4', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 4', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_4', + 'unique_id': '01JTEST0000000000000000000_num_4', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 4', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_5-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_5', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 5', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 5', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_5', + 'unique_id': '01JTEST0000000000000000000_num_5', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_5-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 5', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_5', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_6-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_6', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 6', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 6', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_6', + 'unique_id': '01JTEST0000000000000000000_num_6', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_6-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 6', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_6', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_7-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_7', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 7', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 7', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_7', + 'unique_id': '01JTEST0000000000000000000_num_7', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_7-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 7', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_7', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_8-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_8', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 8', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 8', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_8', + 'unique_id': '01JTEST0000000000000000000_num_8', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_8-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 8', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_8', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_number_9-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_number_9', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Number 9', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Number 9', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'num_9', + 'unique_id': '01JTEST0000000000000000000_num_9', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_number_9-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Number 9', + }), + 'context': , + 'entity_id': 'button.lg_tv_number_9', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_ok-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_ok', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'OK', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'OK', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'ok', + 'unique_id': '01JTEST0000000000000000000_ok', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_ok-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV OK', + }), + 'context': , + 'entity_id': 'button.lg_tv_ok', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_power_off-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_power_off', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power off', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Power off', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'power_off', + 'unique_id': '01JTEST0000000000000000000_power_off', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_power_off-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Power off', + }), + 'context': , + 'entity_id': 'button.lg_tv_power_off', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_power_on-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_power_on', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power on', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Power on', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'power_on', + 'unique_id': '01JTEST0000000000000000000_power_on', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_power_on-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Power on', + }), + 'context': , + 'entity_id': 'button.lg_tv_power_on', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_right-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_right', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Right', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Right', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'right', + 'unique_id': '01JTEST0000000000000000000_right', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_right-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Right', + }), + 'context': , + 'entity_id': 'button.lg_tv_right', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.lg_tv_up-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.lg_tv_up', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Up', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Up', + 'platform': 'lg_infrared', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'up', + 'unique_id': '01JTEST0000000000000000000_up', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.lg_tv_up-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'LG TV Up', + }), + 'context': , + 'entity_id': 'button.lg_tv_up', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- diff --git a/tests/components/lg_infrared/test_button.py b/tests/components/lg_infrared/test_button.py new file mode 100644 index 00000000000..c1079c13f95 --- /dev/null +++ b/tests/components/lg_infrared/test_button.py @@ -0,0 +1,107 @@ +"""Tests for the LG Infrared button platform.""" + +from __future__ import annotations + +from infrared_protocols.codes.lg.tv import LGTVCode +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS +from homeassistant.const import ATTR_ENTITY_ID, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr, entity_registry as er + +from .conftest import MockInfraredEntity +from .utils import check_availability_follows_ir_entity + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.fixture +def platforms() -> list[Platform]: + """Return platforms to set up.""" + return [Platform.BUTTON] + + +@pytest.mark.usefixtures("init_integration") +async def test_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + device_registry: dr.DeviceRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test all button entities are created with correct attributes.""" + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + # Verify all entities belong to the same device + device_entry = device_registry.async_get_device( + identifiers={("lg_infrared", mock_config_entry.entry_id)} + ) + assert device_entry + entity_entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + for entity_entry in entity_entries: + assert entity_entry.device_id == device_entry.id + + +@pytest.mark.parametrize( + ("entity_id", "expected_code"), + [ + ("button.lg_tv_power_on", LGTVCode.POWER_ON), + ("button.lg_tv_power_off", LGTVCode.POWER_OFF), + ("button.lg_tv_hdmi_1", LGTVCode.HDMI_1), + ("button.lg_tv_hdmi_2", LGTVCode.HDMI_2), + ("button.lg_tv_hdmi_3", LGTVCode.HDMI_3), + ("button.lg_tv_hdmi_4", LGTVCode.HDMI_4), + ("button.lg_tv_exit", LGTVCode.EXIT), + ("button.lg_tv_info", LGTVCode.INFO), + ("button.lg_tv_guide", LGTVCode.GUIDE), + ("button.lg_tv_up", LGTVCode.NAV_UP), + ("button.lg_tv_down", LGTVCode.NAV_DOWN), + ("button.lg_tv_left", LGTVCode.NAV_LEFT), + ("button.lg_tv_right", LGTVCode.NAV_RIGHT), + ("button.lg_tv_ok", LGTVCode.OK), + ("button.lg_tv_back", LGTVCode.BACK), + ("button.lg_tv_home", LGTVCode.HOME), + ("button.lg_tv_menu", LGTVCode.MENU), + ("button.lg_tv_input", LGTVCode.INPUT), + ("button.lg_tv_number_0", LGTVCode.NUM_0), + ("button.lg_tv_number_1", LGTVCode.NUM_1), + ("button.lg_tv_number_2", LGTVCode.NUM_2), + ("button.lg_tv_number_3", LGTVCode.NUM_3), + ("button.lg_tv_number_4", LGTVCode.NUM_4), + ("button.lg_tv_number_5", LGTVCode.NUM_5), + ("button.lg_tv_number_6", LGTVCode.NUM_6), + ("button.lg_tv_number_7", LGTVCode.NUM_7), + ("button.lg_tv_number_8", LGTVCode.NUM_8), + ("button.lg_tv_number_9", LGTVCode.NUM_9), + ], +) +@pytest.mark.usefixtures("init_integration") +async def test_button_press_sends_correct_code( + hass: HomeAssistant, + mock_infrared_entity: MockInfraredEntity, + entity_id: str, + expected_code: LGTVCode, +) -> None: + """Test pressing a button sends the correct IR code.""" + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + assert len(mock_infrared_entity.send_command_calls) == 1 + assert mock_infrared_entity.send_command_calls[0] == expected_code + + +@pytest.mark.usefixtures("init_integration") +async def test_button_availability_follows_ir_entity( + hass: HomeAssistant, +) -> None: + """Test button becomes unavailable when IR entity is unavailable.""" + entity_id = "button.lg_tv_power_on" + await check_availability_follows_ir_entity(hass, entity_id) diff --git a/tests/components/lg_infrared/test_media_player.py b/tests/components/lg_infrared/test_media_player.py index 7ff6943335e..87be72f4207 100644 --- a/tests/components/lg_infrared/test_media_player.py +++ b/tests/components/lg_infrared/test_media_player.py @@ -19,11 +19,12 @@ from homeassistant.components.media_player import ( SERVICE_VOLUME_MUTE, SERVICE_VOLUME_UP, ) -from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform +from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from .conftest import MOCK_INFRARED_ENTITY_ID, MockInfraredEntity +from .conftest import MockInfraredEntity +from .utils import check_availability_follows_ir_entity from tests.common import MockConfigEntry, snapshot_platform @@ -99,23 +100,4 @@ async def test_media_player_availability_follows_ir_entity( hass: HomeAssistant, ) -> None: """Test media player becomes unavailable when IR entity is unavailable.""" - # Initially available - state = hass.states.get(MEDIA_PLAYER_ENTITY_ID) - assert state is not None - assert state.state != STATE_UNAVAILABLE - - # Make IR entity unavailable - hass.states.async_set(MOCK_INFRARED_ENTITY_ID, STATE_UNAVAILABLE) - await hass.async_block_till_done() - - state = hass.states.get(MEDIA_PLAYER_ENTITY_ID) - assert state is not None - assert state.state == STATE_UNAVAILABLE - - # Restore IR entity - hass.states.async_set(MOCK_INFRARED_ENTITY_ID, "2026-01-01T00:00:00.000") - await hass.async_block_till_done() - - state = hass.states.get(MEDIA_PLAYER_ENTITY_ID) - assert state is not None - assert state.state != STATE_UNAVAILABLE + await check_availability_follows_ir_entity(hass, MEDIA_PLAYER_ENTITY_ID) diff --git a/tests/components/lg_infrared/utils.py b/tests/components/lg_infrared/utils.py new file mode 100644 index 00000000000..6db180573eb --- /dev/null +++ b/tests/components/lg_infrared/utils.py @@ -0,0 +1,33 @@ +"""Tests for the LG Infrared integration.""" + +from homeassistant.const import STATE_UNAVAILABLE +from homeassistant.core import HomeAssistant + +from .conftest import MOCK_INFRARED_ENTITY_ID + + +async def check_availability_follows_ir_entity( + hass: HomeAssistant, + entity_id: str, +) -> None: + """Check that entity becomes unavailable when IR entity is unavailable.""" + # Initially available + state = hass.states.get(entity_id) + assert state is not None + assert state.state != STATE_UNAVAILABLE + + # Make IR entity unavailable + hass.states.async_set(MOCK_INFRARED_ENTITY_ID, STATE_UNAVAILABLE) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.state == STATE_UNAVAILABLE + + # Restore IR entity + hass.states.async_set(MOCK_INFRARED_ENTITY_ID, "2026-01-01T00:00:00.000") + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.state != STATE_UNAVAILABLE