Fix exceptions when using newer Samsung TVs (#31602)

* try to fix websocket problems

* use tuple

* catch websocket exceptions

* typo
This commit is contained in:
escoand 2020-02-08 12:03:35 +01:00 committed by GitHub
parent baa9184b33
commit 0823ee4385
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 10 deletions

View File

@ -5,6 +5,7 @@ from urllib.parse import urlparse
from samsungctl import Remote from samsungctl import Remote
from samsungctl.exceptions import AccessDenied, UnhandledResponse from samsungctl.exceptions import AccessDenied, UnhandledResponse
import voluptuous as vol import voluptuous as vol
from websocket import WebSocketException
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.ssdp import ( from homeassistant.components.ssdp import (
@ -23,7 +24,7 @@ from homeassistant.const import (
) )
# pylint:disable=unused-import # pylint:disable=unused-import
from .const import CONF_MANUFACTURER, CONF_MODEL, DOMAIN, LOGGER, METHODS from .const import CONF_MANUFACTURER, CONF_MODEL, DOMAIN, LOGGER
DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str, vol.Required(CONF_NAME): str}) DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str, vol.Required(CONF_NAME): str})
@ -32,6 +33,12 @@ RESULT_SUCCESS = "success"
RESULT_NOT_SUCCESSFUL = "not_successful" RESULT_NOT_SUCCESSFUL = "not_successful"
RESULT_NOT_SUPPORTED = "not_supported" RESULT_NOT_SUPPORTED = "not_supported"
SUPPORTED_METHODS = (
{"method": "websocket", "timeout": 1},
# We need this high timeout because waiting for auth popup is just an open socket
{"method": "legacy", "timeout": 31},
)
def _get_ip(host): def _get_ip(host):
if host is None: if host is None:
@ -76,27 +83,25 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
def _try_connect(self): def _try_connect(self):
"""Try to connect and check auth.""" """Try to connect and check auth."""
for method in METHODS: for cfg in SUPPORTED_METHODS:
config = { config = {
"name": "HomeAssistant", "name": "HomeAssistant",
"description": "HomeAssistant", "description": "HomeAssistant",
"id": "ha.component.samsung", "id": "ha.component.samsung",
"host": self._host, "host": self._host,
"method": method,
"port": self._port, "port": self._port,
# We need this high timeout because waiting for auth popup is just an open socket
"timeout": 31,
} }
config.update(cfg)
try: try:
LOGGER.debug("Try config: %s", config) LOGGER.debug("Try config: %s", config)
with Remote(config.copy()): with Remote(config.copy()):
LOGGER.debug("Working config: %s", config) LOGGER.debug("Working config: %s", config)
self._method = method self._method = cfg["method"]
return RESULT_SUCCESS return RESULT_SUCCESS
except AccessDenied: except AccessDenied:
LOGGER.debug("Working but denied config: %s", config) LOGGER.debug("Working but denied config: %s", config)
return RESULT_AUTH_MISSING return RESULT_AUTH_MISSING
except UnhandledResponse: except (UnhandledResponse, WebSocketException):
LOGGER.debug("Working but unsupported config: %s", config) LOGGER.debug("Working but unsupported config: %s", config)
return RESULT_NOT_SUPPORTED return RESULT_NOT_SUPPORTED
except OSError as err: except OSError as err:

View File

@ -9,5 +9,3 @@ DEFAULT_NAME = "Samsung TV"
CONF_MANUFACTURER = "manufacturer" CONF_MANUFACTURER = "manufacturer"
CONF_MODEL = "model" CONF_MODEL = "model"
CONF_ON_ACTION = "turn_on_action" CONF_ON_ACTION = "turn_on_action"
METHODS = ("websocket", "legacy")

View File

@ -4,6 +4,7 @@ from unittest.mock import call, patch
from asynctest import mock from asynctest import mock
import pytest import pytest
from samsungctl.exceptions import AccessDenied, UnhandledResponse from samsungctl.exceptions import AccessDenied, UnhandledResponse
from websocket import WebSocketProtocolException
from homeassistant.components.samsungtv.const import ( from homeassistant.components.samsungtv.const import (
CONF_MANUFACTURER, CONF_MANUFACTURER,
@ -42,7 +43,7 @@ AUTODETECT_WEBSOCKET = {
"method": "websocket", "method": "websocket",
"port": None, "port": None,
"host": "fake_host", "host": "fake_host",
"timeout": 31, "timeout": 1,
} }
AUTODETECT_LEGACY = { AUTODETECT_LEGACY = {
"name": "HomeAssistant", "name": "HomeAssistant",
@ -245,6 +246,28 @@ async def test_ssdp_not_supported(hass):
assert result["reason"] == "not_supported" assert result["reason"] == "not_supported"
async def test_ssdp_not_supported_2(hass):
"""Test starting a flow from discovery for not supported device."""
with patch(
"homeassistant.components.samsungtv.config_flow.Remote",
side_effect=WebSocketProtocolException("Boom"),
), patch("homeassistant.components.samsungtv.config_flow.socket"):
# confirm to add the entry
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "ssdp"}, data=MOCK_SSDP_DATA
)
assert result["type"] == "form"
assert result["step_id"] == "confirm"
# device not supported
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input="whatever"
)
assert result["type"] == "abort"
assert result["reason"] == "not_supported"
async def test_ssdp_not_successful(hass): async def test_ssdp_not_successful(hass):
"""Test starting a flow from discovery but no device found.""" """Test starting a flow from discovery but no device found."""
with patch( with patch(