Handle missing action exceptions in SamsungTV (#143630)

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
Simone Chemelli 2025-05-02 12:39:28 +03:00 committed by GitHub
parent 86b845f04a
commit b0f1c71129
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 19 deletions

View File

@ -46,6 +46,7 @@ from homeassistant.const import (
CONF_TOKEN,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_component
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import format_mac
@ -53,6 +54,7 @@ from homeassistant.util import dt as dt_util
from .const import (
CONF_SESSION_ID,
DOMAIN,
ENCRYPTED_WEBSOCKET_PORT,
LEGACY_PORT,
LOGGER,
@ -371,9 +373,13 @@ class SamsungTVLegacyBridge(SamsungTVBridge):
except (ConnectionClosed, BrokenPipeError):
# BrokenPipe can occur when the commands is sent to fast
self._remote = None
except (UnhandledResponse, AccessDenied):
except (UnhandledResponse, AccessDenied) as err:
# We got a response so it's on.
LOGGER.debug("Failed sending command %s", key, exc_info=True)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="error_sending_command",
translation_placeholders={"error": repr(err), "host": self.host},
) from err
except OSError:
# Different reasons, e.g. hostname not resolveable
pass

View File

@ -29,13 +29,14 @@ from homeassistant.components.media_player import (
MediaType,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.async_ import create_eager_task
from .bridge import SamsungTVWSBridge
from .const import CONF_SSDP_RENDERING_CONTROL_LOCATION, LOGGER
from .const import CONF_SSDP_RENDERING_CONTROL_LOCATION, DOMAIN, LOGGER
from .coordinator import SamsungTVConfigEntry, SamsungTVDataUpdateCoordinator
from .entity import SamsungTVEntity
@ -308,7 +309,12 @@ class SamsungTVDevice(SamsungTVEntity, MediaPlayerEntity):
try:
await dmr_device.async_set_volume_level(volume)
except UpnpActionResponseError as err:
LOGGER.warning("Unable to set volume level on %s: %r", self._host, err)
assert self._host
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="error_set_volume",
translation_placeholders={"error": repr(err), "host": self._host},
) from err
async def async_volume_up(self) -> None:
"""Volume up the media player."""

View File

@ -68,6 +68,12 @@
"service_unsupported": {
"message": "Entity {entity} does not support this action."
},
"error_set_volume": {
"message": "Unable to set volume level on {host}: {error}"
},
"error_sending_command": {
"message": "Unable to send command to {host}: {error}"
},
"encrypted_mode_auth_failed": {
"message": "Token and session ID are required in encrypted mode."
},

View File

@ -77,7 +77,7 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceNotSupported
from homeassistant.exceptions import HomeAssistantError, ServiceNotSupported
from homeassistant.setup import async_setup_component
from . import setup_samsungtv_entry
@ -563,9 +563,11 @@ async def test_send_key_unhandled_response(hass: HomeAssistant, remote: Mock) ->
"""Testing unhandled response exception."""
await setup_samsungtv_entry(hass, MOCK_CONFIG)
remote.control = Mock(side_effect=exceptions.UnhandledResponse("Boom"))
await hass.services.async_call(
MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: ENTITY_ID}, True
)
with pytest.raises(HomeAssistantError) as err:
await hass.services.async_call(
MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: ENTITY_ID}, True
)
assert err.value.translation_key == "error_sending_command"
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ON
@ -1219,9 +1221,7 @@ async def test_websocket_unsupported_remote_control(
@pytest.mark.usefixtures("remotews", "rest_api", "upnp_notify_server")
async def test_volume_control_upnp(
hass: HomeAssistant, dmr_device: Mock, caplog: pytest.LogCaptureFixture
) -> None:
async def test_volume_control_upnp(hass: HomeAssistant, dmr_device: Mock) -> None:
"""Test for Upnp volume control."""
await setup_samsungtv_entry(hass, MOCK_ENTRY_WS)
@ -1237,21 +1237,21 @@ async def test_volume_control_upnp(
True,
)
dmr_device.async_set_volume_level.assert_called_once_with(0.5)
assert "Unable to set volume level on" not in caplog.text
# Upnp action failed
dmr_device.async_set_volume_level.reset_mock()
dmr_device.async_set_volume_level.side_effect = UpnpActionResponseError(
status=500, error_code=501, error_desc="Action Failed"
)
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_SET,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_MEDIA_VOLUME_LEVEL: 0.6},
True,
)
with pytest.raises(HomeAssistantError) as err:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_SET,
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_MEDIA_VOLUME_LEVEL: 0.6},
True,
)
assert err.value.translation_key == "error_set_volume"
dmr_device.async_set_volume_level.assert_called_once_with(0.6)
assert "Unable to set volume level on" in caplog.text
@pytest.mark.usefixtures("remotews", "rest_api")