diff --git a/homeassistant/components/webostv/strings.json b/homeassistant/components/webostv/strings.json index f8d6820da5c6..a6b08cd24370 100644 --- a/homeassistant/components/webostv/strings.json +++ b/homeassistant/components/webostv/strings.json @@ -83,6 +83,9 @@ "notify_icon_not_found": { "message": "Icon {icon_path} not found when sending notification for device {name}" }, + "screen_control_not_supported": { + "message": "{name} does not support turning the screen on or off." + }, "source_not_found": { "message": "Source {source} not found in the sources list for {name}." }, diff --git a/homeassistant/components/webostv/switch.py b/homeassistant/components/webostv/switch.py index 042bc697ef3f..e87363d91cd8 100644 --- a/homeassistant/components/webostv/switch.py +++ b/homeassistant/components/webostv/switch.py @@ -2,10 +2,14 @@ from typing import Any, override +from aiowebostv import WebOsTvServiceNotFoundError + from homeassistant.components.switch import SwitchEntity from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from .const import DOMAIN from .coordinator import WebOsTvConfigEntry from .entity import WebOsTvEntity, cmd @@ -25,17 +29,21 @@ class LgWebOSScreenSwitchEntity(WebOsTvEntity, SwitchEntity): """Representation of a LG webOS TV Screen Switch.""" _attr_translation_key = "screen" + _attr_entity_registry_enabled_default = False def __init__(self, entry: WebOsTvConfigEntry) -> None: """Initialize the screen switch entity.""" super().__init__(entry) self._attr_unique_id = f"{entry.unique_id}_screen" + self._unsupported = False @property @override def available(self) -> bool: """Return true if the entity is available.""" - return super().available and self._client.tv_state.is_on + return ( + super().available and self._client.tv_state.is_on and not self._unsupported + ) @property @override @@ -47,10 +55,23 @@ class LgWebOSScreenSwitchEntity(WebOsTvEntity, SwitchEntity): @override async def async_turn_on(self, **kwargs: Any) -> None: """Turn the screen on.""" - await self._client.set_screen_state(True) + await self._async_set_screen_state(True) @cmd @override async def async_turn_off(self, **kwargs: Any) -> None: """Turn the screen off.""" - await self._client.set_screen_state(False) + await self._async_set_screen_state(False) + + async def _async_set_screen_state(self, state: bool) -> None: + """Set the screen state, marking the switch unsupported on a 404.""" + try: + await self._client.set_screen_state(state) + except WebOsTvServiceNotFoundError as error: + self._unsupported = True + self.async_write_ha_state() + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="screen_control_not_supported", + translation_placeholders={"name": self.coordinator.name}, + ) from error diff --git a/tests/components/webostv/test_switch.py b/tests/components/webostv/test_switch.py index ec044f67139f..b56fcee78c66 100644 --- a/tests/components/webostv/test_switch.py +++ b/tests/components/webostv/test_switch.py @@ -2,7 +2,7 @@ from unittest.mock import AsyncMock -from aiowebostv import WebOsTvCommandError +from aiowebostv import WebOsTvCommandError, WebOsTvServiceNotFoundError import pytest from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN @@ -30,18 +30,18 @@ async def test_screen_switch_setup( client: AsyncMock, entity_registry: er.EntityRegistry, ) -> None: - """Test setup of LG webOS TV screen switch.""" + """Test the LG webOS TV screen switch is registered but disabled.""" await setup_webostv(hass) entry = entity_registry.async_get(SWITCH_ENTITY_ID) assert entry is not None assert entry.unique_id == f"{FAKE_UUID}_screen" + assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION - state = hass.states.get(SWITCH_ENTITY_ID) - assert state is not None - assert state.state == STATE_OFF + assert hass.states.get(SWITCH_ENTITY_ID) is None +@pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_screen_switch_state_updates( hass: HomeAssistant, client: AsyncMock, @@ -71,6 +71,7 @@ async def test_screen_switch_state_updates( assert state.state == STATE_UNAVAILABLE +@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.parametrize( ("service", "screen_state"), [ @@ -97,6 +98,7 @@ async def test_screen_switch_commands( client.set_screen_state.assert_called_once_with(screen_state) +@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.parametrize("service", [SERVICE_TURN_ON, SERVICE_TURN_OFF]) async def test_screen_switch_command_error( hass: HomeAssistant, @@ -117,3 +119,32 @@ async def test_screen_switch_command_error( assert err.value.translation_domain == DOMAIN assert err.value.translation_key == "communication_error" + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +@pytest.mark.parametrize("service", [SERVICE_TURN_ON, SERVICE_TURN_OFF]) +async def test_screen_switch_not_supported( + hass: HomeAssistant, + client: AsyncMock, + service: str, +) -> None: + """Test a TV without screen control raises a translated error.""" + await setup_webostv(hass) + client.set_screen_state.side_effect = WebOsTvServiceNotFoundError( + "404 no such service or method" + ) + + with pytest.raises(HomeAssistantError) as err: + await hass.services.async_call( + SWITCH_DOMAIN, + service, + {ATTR_ENTITY_ID: SWITCH_ENTITY_ID}, + blocking=True, + ) + + assert err.value.translation_domain == DOMAIN + assert err.value.translation_key == "screen_control_not_supported" + + state = hass.states.get(SWITCH_ENTITY_ID) + assert state is not None + assert state.state == STATE_UNAVAILABLE