diff --git a/homeassistant/components/hue/config_flow.py b/homeassistant/components/hue/config_flow.py index 3df17baad16..d87da5b5ac0 100644 --- a/homeassistant/components/hue/config_flow.py +++ b/homeassistant/components/hue/config_flow.py @@ -4,7 +4,6 @@ from __future__ import annotations import asyncio import logging from typing import Any -from urllib.parse import urlparse import aiohttp from aiohue import LinkButtonNotPressed, create_app_key @@ -15,7 +14,7 @@ import slugify as unicode_slug import voluptuous as vol from homeassistant import config_entries -from homeassistant.components import ssdp, zeroconf +from homeassistant.components import zeroconf from homeassistant.const import CONF_API_KEY, CONF_HOST from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult @@ -201,53 +200,6 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): }, ) - async def async_step_ssdp(self, discovery_info: ssdp.SsdpServiceInfo) -> FlowResult: - """Handle a discovered Hue bridge. - - This flow is triggered by the SSDP component. It will check if the - host is already configured and delegate to the import step if not. - """ - # Filter out non-Hue bridges #1 - if ( - discovery_info.upnp.get(ssdp.ATTR_UPNP_MANUFACTURER_URL) - not in HUE_MANUFACTURERURL - ): - return self.async_abort(reason="not_hue_bridge") - - # Filter out non-Hue bridges #2 - if any( - name in discovery_info.upnp.get(ssdp.ATTR_UPNP_FRIENDLY_NAME, "") - for name in HUE_IGNORED_BRIDGE_NAMES - ): - return self.async_abort(reason="not_hue_bridge") - - if ( - not discovery_info.ssdp_location - or ssdp.ATTR_UPNP_SERIAL not in discovery_info.upnp - ): - return self.async_abort(reason="not_hue_bridge") - - url = urlparse(discovery_info.ssdp_location) - if not url.hostname: - return self.async_abort(reason="not_hue_bridge") - - # Ignore if host is IPv6 - if is_ipv6_address(url.hostname): - return self.async_abort(reason="invalid_host") - - # abort if we already have exactly this bridge id/host - # reload the integration if the host got updated - bridge_id = normalize_bridge_id(discovery_info.upnp[ssdp.ATTR_UPNP_SERIAL]) - await self.async_set_unique_id(bridge_id) - self._abort_if_unique_id_configured( - updates={CONF_HOST: url.hostname}, reload_on_update=True - ) - - self.bridge = await self._get_bridge( - url.hostname, discovery_info.upnp[ssdp.ATTR_UPNP_SERIAL] - ) - return await self.async_step_link() - async def async_step_zeroconf( self, discovery_info: zeroconf.ZeroconfServiceInfo ) -> FlowResult: diff --git a/homeassistant/components/hue/manifest.json b/homeassistant/components/hue/manifest.json index 0c460d1dd36..efe499357fb 100644 --- a/homeassistant/components/hue/manifest.json +++ b/homeassistant/components/hue/manifest.json @@ -4,20 +4,6 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/hue", "requirements": ["aiohue==4.6.1"], - "ssdp": [ - { - "manufacturer": "Royal Philips Electronics", - "modelName": "Philips hue bridge 2012" - }, - { - "manufacturer": "Royal Philips Electronics", - "modelName": "Philips hue bridge 2015" - }, - { - "manufacturer": "Signify", - "modelName": "Philips hue bridge 2015" - } - ], "homekit": { "models": ["BSB002"] }, diff --git a/homeassistant/generated/ssdp.py b/homeassistant/generated/ssdp.py index 6599136b747..ca6a22e85d6 100644 --- a/homeassistant/generated/ssdp.py +++ b/homeassistant/generated/ssdp.py @@ -155,20 +155,6 @@ SSDP = { "manufacturer": "SOYEA TECHNOLOGY CO., LTD.", }, ], - "hue": [ - { - "manufacturer": "Royal Philips Electronics", - "modelName": "Philips hue bridge 2012", - }, - { - "manufacturer": "Royal Philips Electronics", - "modelName": "Philips hue bridge 2015", - }, - { - "manufacturer": "Signify", - "modelName": "Philips hue bridge 2015", - }, - ], "hyperion": [ { "manufacturer": "Hyperion Open Source Ambient Lighting", diff --git a/tests/components/hue/test_config_flow.py b/tests/components/hue/test_config_flow.py index d8be19f92c6..aad574bd1db 100644 --- a/tests/components/hue/test_config_flow.py +++ b/tests/components/hue/test_config_flow.py @@ -8,7 +8,7 @@ import pytest import voluptuous as vol from homeassistant import config_entries -from homeassistant.components import ssdp, zeroconf +from homeassistant.components import zeroconf from homeassistant.components.hue import config_flow, const from homeassistant.components.hue.errors import CannotConnect from homeassistant.helpers import device_registry as dr @@ -327,176 +327,6 @@ async def test_flow_link_cannot_connect(hass): assert result["reason"] == "cannot_connect" -@pytest.mark.parametrize("mf_url", config_flow.HUE_MANUFACTURERURL) -async def test_bridge_ssdp(hass, mf_url, aioclient_mock): - """Test a bridge being discovered.""" - create_mock_api_discovery(aioclient_mock, [("0.0.0.0", "1234")]) - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location="http://0.0.0.0/", - upnp={ - ssdp.ATTR_UPNP_MANUFACTURER_URL: mf_url, - ssdp.ATTR_UPNP_SERIAL: "1234", - }, - ), - ) - - assert result["type"] == "form" - assert result["step_id"] == "link" - - -async def test_bridge_ssdp_discover_other_bridge(hass): - """Test that discovery ignores other bridges.""" - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - upnp={ssdp.ATTR_UPNP_MANUFACTURER_URL: "http://www.notphilips.com"}, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "not_hue_bridge" - - -async def test_bridge_ssdp_emulated_hue(hass): - """Test if discovery info is from an emulated hue instance.""" - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location="http://0.0.0.0/", - upnp={ - ssdp.ATTR_UPNP_FRIENDLY_NAME: "Home Assistant Bridge", - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - ssdp.ATTR_UPNP_SERIAL: "1234", - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "not_hue_bridge" - - -async def test_bridge_ssdp_missing_location(hass): - """Test if discovery info is missing a location attribute.""" - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - upnp={ - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - ssdp.ATTR_UPNP_SERIAL: "1234", - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "not_hue_bridge" - - -async def test_bridge_ssdp_missing_serial(hass): - """Test if discovery info is a serial attribute.""" - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location="http://0.0.0.0/", - upnp={ - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "not_hue_bridge" - - -@pytest.mark.parametrize( - "location,reason", - ( - ("http:///", "not_hue_bridge"), - ("http://[fd00::eeb5:faff:fe84:b17d]/description.xml", "invalid_host"), - ), -) -async def test_bridge_ssdp_invalid_location(hass, location, reason): - """Test if discovery info is a serial attribute.""" - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location=location, - upnp={ - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - ssdp.ATTR_UPNP_SERIAL: "1234", - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == reason - - -async def test_bridge_ssdp_espalexa(hass): - """Test if discovery info is from an Espalexa based device.""" - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location="http://0.0.0.0/", - upnp={ - ssdp.ATTR_UPNP_FRIENDLY_NAME: "Espalexa (0.0.0.0)", - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - ssdp.ATTR_UPNP_SERIAL: "1234", - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "not_hue_bridge" - - -async def test_bridge_ssdp_already_configured(hass, aioclient_mock): - """Test if a discovered bridge has already been configured.""" - create_mock_api_discovery(aioclient_mock, [("0.0.0.0", "1234")]) - MockConfigEntry( - domain="hue", unique_id="1234", data={"host": "0.0.0.0"} - ).add_to_hass(hass) - - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location="http://0.0.0.0/", - upnp={ - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - ssdp.ATTR_UPNP_SERIAL: "1234", - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "already_configured" - - async def test_import_with_no_config(hass, aioclient_mock): """Test importing a host without an existing config file.""" create_mock_api_discovery(aioclient_mock, [("0.0.0.0", "1234")]) @@ -634,33 +464,6 @@ async def test_bridge_homekit_already_configured(hass, aioclient_mock): assert result["reason"] == "already_configured" -async def test_ssdp_discovery_update_configuration(hass, aioclient_mock): - """Test if a discovered bridge is configured and updated with new host.""" - create_mock_api_discovery(aioclient_mock, [("1.1.1.1", "aabbccddeeff")]) - entry = MockConfigEntry( - domain="hue", unique_id="aabbccddeeff", data={"host": "0.0.0.0"} - ) - entry.add_to_hass(hass) - - result = await hass.config_entries.flow.async_init( - const.DOMAIN, - context={"source": config_entries.SOURCE_SSDP}, - data=ssdp.SsdpServiceInfo( - ssdp_usn="mock_usn", - ssdp_st="mock_st", - ssdp_location="http://1.1.1.1/", - upnp={ - ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], - ssdp.ATTR_UPNP_SERIAL: "aabbccddeeff", - }, - ), - ) - - assert result["type"] == "abort" - assert result["reason"] == "already_configured" - assert entry.data["host"] == "1.1.1.1" - - async def test_options_flow_v1(hass): """Test options config flow for a V1 bridge.""" entry = MockConfigEntry( @@ -772,7 +575,7 @@ async def test_bridge_zeroconf_already_exists(hass, aioclient_mock): ) entry = MockConfigEntry( domain="hue", - source=config_entries.SOURCE_SSDP, + source=config_entries.SOURCE_HOMEKIT, data={"host": "0.0.0.0"}, unique_id="ecb5faabcabc", )