From 521b6455ee1bbdbf0420b1727036aaa3eeff8c95 Mon Sep 17 00:00:00 2001 From: Michael <35783820+mib1185@users.noreply.github.com> Date: Wed, 30 Sep 2026 11:06:34 +0200 Subject: [PATCH] Ignore non smarthome capabile device during discovery in FRITZ!SmartHome (#183708) --- .../components/fritzbox/config_flow.py | 17 +++++++++++ tests/components/fritzbox/test_config_flow.py | 29 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/homeassistant/components/fritzbox/config_flow.py b/homeassistant/components/fritzbox/config_flow.py index 9a028306f07c..4f545bce03f8 100644 --- a/homeassistant/components/fritzbox/config_flow.py +++ b/homeassistant/components/fritzbox/config_flow.py @@ -110,6 +110,20 @@ class FritzboxConfigFlow(ConfigFlow, domain=DOMAIN): return RESULT_NO_DEVICES_FOUND return RESULT_SUCCESS + async def async_has_smarthome_capabilities(self) -> bool | None: + """Test if the device has smarthome capabilities.""" + return await self.hass.async_add_executor_job(self._has_smarthome_capabilities) + + def _has_smarthome_capabilities(self) -> bool | None: + """Test if the device has smarthome capabilities.""" + fritzbox = Fritzhome( + host=self._url, + user=None, + password=None, + ssl_verify=False, + ) + return fritzbox.has_smarthome_capabilities() # type: ignore[no-any-return] + @override async def async_step_user( self, user_input: dict[str, Any] | None = None @@ -178,6 +192,9 @@ class FritzboxConfigFlow(ConfigFlow, domain=DOMAIN): self.hass.config_entries.async_update_entry(entry, unique_id=uuid) return self.async_abort(reason="already_configured") + if await self.async_has_smarthome_capabilities() is False: + return self.async_abort(reason="not_supported") + self._name = str(discovery_info.upnp.get(ATTR_UPNP_FRIENDLY_NAME) or self._url) self.context["title_placeholders"] = {"name": self._name} diff --git a/tests/components/fritzbox/test_config_flow.py b/tests/components/fritzbox/test_config_flow.py index 04aa7c6ccefa..7703fc5c477a 100644 --- a/tests/components/fritzbox/test_config_flow.py +++ b/tests/components/fritzbox/test_config_flow.py @@ -447,6 +447,35 @@ async def test_ssdp_not_supported(hass: HomeAssistant, fritz: Mock) -> None: assert result["reason"] == "not_supported" +@pytest.mark.parametrize( + ("capabilities", "expected_type", "expected_step", "expected_reason"), + [ + (True, FlowResultType.FORM, "confirm", None), + (False, FlowResultType.ABORT, None, "not_supported"), + (None, FlowResultType.FORM, "confirm", None), + ], +) +async def test_ssdp_smarthome_capabilities( + hass: HomeAssistant, + fritz: Mock, + capabilities: bool | None, + expected_type: str, + expected_step: str | None, + expected_reason: str | None, +) -> None: + """Test starting a flow from discovery with SmartHome capabilities.""" + fritz().has_smarthome_capabilities.return_value = capabilities + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_SSDP}, data=MOCK_SSDP_DATA["ip4_valid"] + ) + + assert result["type"] is expected_type + assert result.get("step_id") == expected_step + assert result.get("reason") == expected_reason + fritz().has_smarthome_capabilities.assert_called_once_with() + + async def test_ssdp_already_in_progress_unique_id( hass: HomeAssistant, fritz: Mock ) -> None: