diff --git a/homeassistant/components/fritzbox/config_flow.py b/homeassistant/components/fritzbox/config_flow.py index b4265aa01fea..25a81333bd67 100644 --- a/homeassistant/components/fritzbox/config_flow.py +++ b/homeassistant/components/fritzbox/config_flow.py @@ -2,6 +2,7 @@ from urllib.parse import urlparse from pyfritzhome import Fritzhome, LoginError +from requests.exceptions import HTTPError import voluptuous as vol from homeassistant import config_entries @@ -32,6 +33,7 @@ DATA_SCHEMA_CONFIRM = vol.Schema( RESULT_AUTH_FAILED = "auth_failed" RESULT_NOT_FOUND = "not_found" +RESULT_NOT_SUPPORTED = "not_supported" RESULT_SUCCESS = "success" @@ -67,12 +69,15 @@ class FritzboxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) try: fritzbox.login() + fritzbox.get_device_elements() fritzbox.logout() return RESULT_SUCCESS - except OSError: - return RESULT_NOT_FOUND except LoginError: return RESULT_AUTH_FAILED + except HTTPError: + return RESULT_NOT_SUPPORTED + except OSError: + return RESULT_NOT_FOUND async def async_step_import(self, user_input=None): """Handle configuration by yaml file.""" @@ -129,7 +134,7 @@ class FritzboxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_abort(reason="already_configured") self._host = host - self._name = user_input[ATTR_UPNP_FRIENDLY_NAME] + self._name = user_input.get(ATTR_UPNP_FRIENDLY_NAME) or host self.context["title_placeholders"] = {"name": self._name} return await self.async_step_confirm() diff --git a/homeassistant/components/fritzbox/strings.json b/homeassistant/components/fritzbox/strings.json index 4cb5b7bcdcca..227aeedf84d4 100644 --- a/homeassistant/components/fritzbox/strings.json +++ b/homeassistant/components/fritzbox/strings.json @@ -21,7 +21,8 @@ "abort": { "already_in_progress": "AVM FRITZ!Box configuration is already in progress.", "already_configured": "This AVM FRITZ!Box is already configured.", - "not_found": "No supported AVM FRITZ!Box found on the network." + "not_found": "No supported AVM FRITZ!Box found on the network.", + "not_supported": "Connected to AVM FRITZ!Box but it's unable to control Smart Home devices." }, "error": { "auth_failed": "Username and/or password are incorrect." diff --git a/tests/components/fritzbox/test_config_flow.py b/tests/components/fritzbox/test_config_flow.py index c73578de646b..8bfd992347f5 100644 --- a/tests/components/fritzbox/test_config_flow.py +++ b/tests/components/fritzbox/test_config_flow.py @@ -4,6 +4,7 @@ from unittest.mock import Mock, patch from pyfritzhome import LoginError import pytest +from requests.exceptions import HTTPError from homeassistant.components.fritzbox.const import DOMAIN from homeassistant.components.ssdp import ( @@ -121,6 +122,28 @@ async def test_ssdp(hass: HomeAssistantType, fritz: Mock): assert result["result"].unique_id == "only-a-test" +async def test_ssdp_no_friendly_name(hass: HomeAssistantType, fritz: Mock): + """Test starting a flow from discovery without friendly name.""" + MOCK_NO_NAME = MOCK_SSDP_DATA.copy() + del MOCK_NO_NAME[ATTR_UPNP_FRIENDLY_NAME] + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": "ssdp"}, data=MOCK_NO_NAME + ) + assert result["type"] == "form" + assert result["step_id"] == "confirm" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_PASSWORD: "fake_pass", CONF_USERNAME: "fake_user"}, + ) + assert result["type"] == "create_entry" + assert result["title"] == "fake_host" + assert result["data"][CONF_HOST] == "fake_host" + assert result["data"][CONF_PASSWORD] == "fake_pass" + assert result["data"][CONF_USERNAME] == "fake_user" + assert result["result"].unique_id == "only-a-test" + + async def test_ssdp_auth_failed(hass: HomeAssistantType, fritz: Mock): """Test starting a flow from discovery with authentication failure.""" fritz().login.side_effect = LoginError("Boom") @@ -159,6 +182,24 @@ async def test_ssdp_not_successful(hass: HomeAssistantType, fritz: Mock): assert result["reason"] == "not_found" +async def test_ssdp_not_supported(hass: HomeAssistantType, fritz: Mock): + """Test starting a flow from discovery with unsupported device.""" + fritz().get_device_elements.side_effect = HTTPError("Boom") + + 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" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_PASSWORD: "whatever", CONF_USERNAME: "whatever"}, + ) + assert result["type"] == "abort" + assert result["reason"] == "not_supported" + + async def test_ssdp_already_in_progress_unique_id(hass: HomeAssistantType, fritz: Mock): """Test starting a flow from discovery twice.""" result = await hass.config_entries.flow.async_init(