Adjust ms.remote.control error logging in SamsungTV (#67988)

Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
epenet 2022-03-12 12:20:04 +01:00 committed by GitHub
parent 0d8f649bd6
commit 23b8229143
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 6 deletions

View File

@ -12,6 +12,7 @@ from samsungctl.exceptions import AccessDenied, ConnectionClosed, UnhandledRespo
from samsungtvws.async_remote import SamsungTVWSAsyncRemote from samsungtvws.async_remote import SamsungTVWSAsyncRemote
from samsungtvws.async_rest import SamsungTVAsyncRest from samsungtvws.async_rest import SamsungTVAsyncRest
from samsungtvws.command import SamsungTVCommand from samsungtvws.command import SamsungTVCommand
from samsungtvws.event import MS_ERROR_EVENT
from samsungtvws.exceptions import ConnectionFailure, HttpApiError from samsungtvws.exceptions import ConnectionFailure, HttpApiError
from samsungtvws.remote import ChannelEmitCommand, SendRemoteKey from samsungtvws.remote import ChannelEmitCommand, SendRemoteKey
from websockets.exceptions import ConnectionClosedError, WebSocketException from websockets.exceptions import ConnectionClosedError, WebSocketException
@ -460,7 +461,7 @@ class SamsungTVWSBridge(SamsungTVBridge):
name=VALUE_CONF_NAME, name=VALUE_CONF_NAME,
) )
try: try:
await self._remote.start_listening() await self._remote.start_listening(self._remote_event)
except ConnectionClosedError as err: except ConnectionClosedError as err:
# This is only happening when the auth was switched to DENY # This is only happening when the auth was switched to DENY
# A removed auth will lead to socket timeout because waiting # A removed auth will lead to socket timeout because waiting
@ -498,6 +499,21 @@ class SamsungTVWSBridge(SamsungTVBridge):
self._notify_new_token_callback() self._notify_new_token_callback()
return self._remote return self._remote
@staticmethod
def _remote_event(event: str, response: Any) -> None:
"""Received event from remote websocket."""
if event == MS_ERROR_EVENT:
# { 'event': 'ms.error',
# 'data': {'message': 'unrecognized method value : ms.remote.control'}}
if (data := response.get("data")) and (
message := data.get("message")
) == "unrecognized method value : ms.remote.control":
LOGGER.error(
"Your TV seems to be unsupported by "
"SamsungTVWSBridge and may need a PIN: '%s'",
message,
)
async def async_power_off(self) -> None: async def async_power_off(self) -> None:
"""Send power off command to remote.""" """Send power off command to remote."""
if self._get_device_spec("FrameTVSupport") == "true": if self._get_device_spec("FrameTVSupport") == "true":

View File

@ -1,5 +1,9 @@
"""Fixtures for Samsung TV.""" """Fixtures for Samsung TV."""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from datetime import datetime from datetime import datetime
from typing import Any
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
import pytest import pytest
@ -48,14 +52,27 @@ def rest_api_fixture() -> Mock:
@pytest.fixture(name="remotews") @pytest.fixture(name="remotews")
def remotews_fixture() -> Mock: def remotews_fixture() -> Mock:
"""Patch the samsungtvws SamsungTVWS.""" """Patch the samsungtvws SamsungTVWS."""
remotews = Mock(SamsungTVWSAsyncRemote)
remotews.__aenter__ = AsyncMock(return_value=remotews)
remotews.__aexit__ = AsyncMock()
remotews.app_list.return_value = SAMPLE_APP_LIST
remotews.token = "FAKE_TOKEN"
def _start_listening(
ws_event_callback: Callable[[str, Any], Awaitable[None] | None] | None = None
):
remotews.ws_event_callback = ws_event_callback
def _mock_ws_event_callback(event: str, response: Any):
if remotews.ws_event_callback:
remotews.ws_event_callback(event, response)
remotews.start_listening.side_effect = _start_listening
remotews.raise_mock_ws_event_callback = Mock(side_effect=_mock_ws_event_callback)
with patch( with patch(
"homeassistant.components.samsungtv.bridge.SamsungTVWSAsyncRemote", "homeassistant.components.samsungtv.bridge.SamsungTVWSAsyncRemote",
) as remotews_class: ) as remotews_class:
remotews = Mock(SamsungTVWSAsyncRemote)
remotews.__aenter__ = AsyncMock(return_value=remotews)
remotews.__aexit__ = AsyncMock()
remotews.app_list.return_value = SAMPLE_APP_LIST
remotews.token = "FAKE_TOKEN"
remotews_class.return_value = remotews remotews_class.return_value = remotews
yield remotews yield remotews

View File

@ -1066,3 +1066,40 @@ async def test_select_source_app(hass: HomeAssistant, remotews: Mock) -> None:
assert len(commands) == 1 assert len(commands) == 1
assert isinstance(commands[0], ChannelEmitCommand) assert isinstance(commands[0], ChannelEmitCommand)
assert commands[0].params["data"]["appId"] == "3201608010191" assert commands[0].params["data"]["appId"] == "3201608010191"
async def test_websocket_unsupported_remote_control(
hass: HomeAssistant, remotews: Mock, caplog: pytest.LogCaptureFixture
) -> None:
"""Test for turn_off."""
with patch(
"homeassistant.components.samsungtv.bridge.Remote",
side_effect=[OSError("Boom"), DEFAULT_MOCK],
):
await setup_samsungtv(hass, MOCK_CONFIGWS)
remotews.send_command.reset_mock()
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID}, True
)
remotews.raise_mock_ws_event_callback(
"ms.error",
{
"event": "ms.error",
"data": {"message": "unrecognized method value : ms.remote.control"},
},
)
# key called
assert remotews.send_command.call_count == 1
commands = remotews.send_command.call_args_list[0].args[0]
assert len(commands) == 1
assert isinstance(commands[0], SendRemoteKey)
assert commands[0].params["DataOfCmd"] == "KEY_POWER"
# error logged
assert (
"Your TV seems to be unsupported by SamsungTVWSBridge and may need a PIN: "
"'unrecognized method value : ms.remote.control'" in caplog.text
)