diff --git a/homeassistant/components/braviatv/config_flow.py b/homeassistant/components/braviatv/config_flow.py index 660e2e83ea1..d7db38c5c2a 100644 --- a/homeassistant/components/braviatv/config_flow.py +++ b/homeassistant/components/braviatv/config_flow.py @@ -4,6 +4,7 @@ import logging import re from bravia_tv import BraviaRC +from bravia_tv.braviarc import NoIPControl import voluptuous as vol from homeassistant import config_entries, exceptions @@ -51,7 +52,7 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def init_device(self, pin): """Initialize Bravia TV device.""" await self.hass.async_add_executor_job( - self.braviarc.connect, pin, CLIENTID_PREFIX, NICKNAME, + self.braviarc.connect, pin, CLIENTID_PREFIX, NICKNAME ) if not self.braviarc.is_connected(): @@ -85,6 +86,9 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): except CannotConnect: _LOGGER.error("Import aborted, cannot connect to %s", self.host) return self.async_abort(reason="cannot_connect") + except NoIPControl: + _LOGGER.error("IP Control is disabled in the TV settings") + return self.async_abort(reason="no_ip_control") except ModelNotSupported: _LOGGER.error("Import aborted, your TV is not supported") return self.async_abort(reason="unsupported_model") @@ -129,9 +133,12 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_create_entry(title=self.title, data=user_input) # Connecting with th PIN "0000" to start the pairing process on the TV. - await self.hass.async_add_executor_job( - self.braviarc.connect, "0000", CLIENTID_PREFIX, NICKNAME, - ) + try: + await self.hass.async_add_executor_job( + self.braviarc.connect, "0000", CLIENTID_PREFIX, NICKNAME + ) + except NoIPControl: + return self.async_abort(reason="no_ip_control") return self.async_show_form( step_id="authorize", @@ -156,7 +163,7 @@ class BraviaTVOptionsFlowHandler(config_entries.OptionsFlow): self.braviarc = self.hass.data[DOMAIN][self.config_entry.entry_id][BRAVIARC] if not self.braviarc.is_connected(): await self.hass.async_add_executor_job( - self.braviarc.connect, self.pin, CLIENTID_PREFIX, NICKNAME, + self.braviarc.connect, self.pin, CLIENTID_PREFIX, NICKNAME ) content_mapping = await self.hass.async_add_executor_job( diff --git a/homeassistant/components/braviatv/manifest.json b/homeassistant/components/braviatv/manifest.json index 0936c1f9088..7ed09ee018d 100644 --- a/homeassistant/components/braviatv/manifest.json +++ b/homeassistant/components/braviatv/manifest.json @@ -2,7 +2,7 @@ "domain": "braviatv", "name": "Sony Bravia TV", "documentation": "https://www.home-assistant.io/integrations/braviatv", - "requirements": ["bravia-tv==1.0.4"], + "requirements": ["bravia-tv==1.0.5"], "codeowners": ["@robbiet480", "@bieniu"], "config_flow": true } diff --git a/homeassistant/components/braviatv/media_player.py b/homeassistant/components/braviatv/media_player.py index eb75542460f..f6c023481c0 100644 --- a/homeassistant/components/braviatv/media_player.py +++ b/homeassistant/components/braviatv/media_player.py @@ -2,6 +2,7 @@ import asyncio import logging +from bravia_tv.braviarc import NoIPControl import voluptuous as vol from homeassistant.components.media_player import ( @@ -162,9 +163,12 @@ class BraviaTVDevice(MediaPlayerEntity): ) if power_status == "active": if self._need_refresh: - connected = await self.hass.async_add_executor_job( - self._braviarc.connect, self._pin, CLIENTID_PREFIX, NICKNAME - ) + try: + connected = await self.hass.async_add_executor_job( + self._braviarc.connect, self._pin, CLIENTID_PREFIX, NICKNAME + ) + except NoIPControl: + _LOGGER.error("IP Control is disabled in the TV settings") self._need_refresh = False else: connected = self._braviarc.is_connected() diff --git a/homeassistant/components/braviatv/strings.json b/homeassistant/components/braviatv/strings.json index ca432270cbb..c066f91d395 100644 --- a/homeassistant/components/braviatv/strings.json +++ b/homeassistant/components/braviatv/strings.json @@ -22,7 +22,8 @@ "unsupported_model": "Your TV model is not supported." }, "abort": { - "already_configured": "This TV is already configured." + "already_configured": "This TV is already configured.", + "no_ip_control": "IP Control is disabled on your TV or the TV is not supported." } }, "options": { diff --git a/requirements_all.txt b/requirements_all.txt index 95a649b2d85..ecd24e3ced4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -371,7 +371,7 @@ bomradarloop==0.1.4 boto3==1.9.252 # homeassistant.components.braviatv -bravia-tv==1.0.4 +bravia-tv==1.0.5 # homeassistant.components.broadlink broadlink==0.14.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index eb0f25d0a37..693c6bdb060 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -159,7 +159,7 @@ blebox_uniapi==1.3.2 bomradarloop==0.1.4 # homeassistant.components.braviatv -bravia-tv==1.0.4 +bravia-tv==1.0.5 # homeassistant.components.broadlink broadlink==0.14.0 diff --git a/tests/components/braviatv/test_config_flow.py b/tests/components/braviatv/test_config_flow.py index 87fa26c242a..c6f76105cfc 100644 --- a/tests/components/braviatv/test_config_flow.py +++ b/tests/components/braviatv/test_config_flow.py @@ -1,4 +1,6 @@ """Define tests for the Bravia TV config flow.""" +from bravia_tv.braviarc import NoIPControl + from homeassistant import data_entry_flow from homeassistant.components.braviatv.const import CONF_IGNORED_SOURCES, DOMAIN from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER @@ -28,14 +30,8 @@ BRAVIA_SOURCE_LIST = { "AV/Component": "extInput:component?port=1", } -IMPORT_CONFIG_HOSTNAME = { - CONF_HOST: "bravia-host", - CONF_PIN: "1234", -} -IMPORT_CONFIG_IP = { - CONF_HOST: "10.10.10.12", - CONF_PIN: "1234", -} +IMPORT_CONFIG_HOSTNAME = {CONF_HOST: "bravia-host", CONF_PIN: "1234"} +IMPORT_CONFIG_IP = {CONF_HOST: "10.10.10.12", CONF_PIN: "1234"} async def test_show_form(hass): @@ -58,7 +54,7 @@ async def test_import(hass): "homeassistant.components.braviatv.async_setup_entry", return_value=True ): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_HOSTNAME, + DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_HOSTNAME ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY @@ -77,7 +73,7 @@ async def test_import_cannot_connect(hass): "bravia_tv.BraviaRC.is_connected", return_value=False ): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_HOSTNAME, + DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_HOSTNAME ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT @@ -90,13 +86,24 @@ async def test_import_model_unsupported(hass): "bravia_tv.BraviaRC.is_connected", return_value=True ), patch("bravia_tv.BraviaRC.get_system_info", return_value={}): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_IP, + DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_IP ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "unsupported_model" +async def test_import_no_ip_control(hass): + """Test that errors are shown when IP Control is disabled on the TV during import.""" + with patch("bravia_tv.BraviaRC.connect", side_effect=NoIPControl("No IP Control")): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_IP + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "no_ip_control" + + async def test_import_duplicate_error(hass): """Test that errors are shown when duplicates are added during import.""" config_entry = MockConfigEntry( @@ -116,7 +123,7 @@ async def test_import_duplicate_error(hass): ), patch("bravia_tv.BraviaRC.get_system_info", return_value=BRAVIA_SYSTEM_INFO): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_HOSTNAME, + DOMAIN, context={"source": SOURCE_IMPORT}, data=IMPORT_CONFIG_HOSTNAME ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT @@ -136,7 +143,7 @@ async def test_authorize_cannot_connect(hass): """Test that errors are shown when cannot connect to host at the authorize step.""" with patch("bravia_tv.BraviaRC.connect", return_value=True): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "bravia-host"}, + DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "bravia-host"} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={CONF_PIN: "1234"} @@ -151,7 +158,7 @@ async def test_authorize_model_unsupported(hass): "bravia_tv.BraviaRC.is_connected", return_value=True ), patch("bravia_tv.BraviaRC.get_system_info", return_value={}): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "10.10.10.12"}, + DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "10.10.10.12"} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={CONF_PIN: "1234"} @@ -160,6 +167,17 @@ async def test_authorize_model_unsupported(hass): assert result["errors"] == {"base": "unsupported_model"} +async def test_authorize_no_ip_control(hass): + """Test that errors are shown when IP Control is disabled on the TV.""" + with patch("bravia_tv.BraviaRC.connect", side_effect=NoIPControl("No IP Control")): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "bravia-host"} + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "no_ip_control" + + async def test_duplicate_error(hass): """Test that errors are shown when duplicates are added.""" config_entry = MockConfigEntry( @@ -179,7 +197,7 @@ async def test_duplicate_error(hass): ), patch("bravia_tv.BraviaRC.get_system_info", return_value=BRAVIA_SYSTEM_INFO): result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "bravia-host"}, + DOMAIN, context={"source": SOURCE_USER}, data={CONF_HOST: "bravia-host"} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={CONF_PIN: "1234"}