diff --git a/homeassistant/components/nanoleaf/config_flow.py b/homeassistant/components/nanoleaf/config_flow.py index d5fc023d3a1..0f4f8ff75bd 100644 --- a/homeassistant/components/nanoleaf/config_flow.py +++ b/homeassistant/components/nanoleaf/config_flow.py @@ -92,25 +92,42 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Handle Nanoleaf Zeroconf discovery.""" _LOGGER.debug("Zeroconf discovered: %s", discovery_info) - return await self._async_discovery_handler(discovery_info) + return await self._async_homekit_zeroconf_discovery_handler(discovery_info) async def async_step_homekit(self, discovery_info: DiscoveryInfoType) -> FlowResult: """Handle Nanoleaf Homekit discovery.""" _LOGGER.debug("Homekit discovered: %s", discovery_info) - return await self._async_discovery_handler(discovery_info) + return await self._async_homekit_zeroconf_discovery_handler(discovery_info) - async def _async_discovery_handler( + async def _async_homekit_zeroconf_discovery_handler( self, discovery_info: DiscoveryInfoType + ) -> FlowResult: + """Handle Nanoleaf Homekit and Zeroconf discovery.""" + return await self._async_discovery_handler( + discovery_info["host"], + discovery_info["name"].replace(f".{discovery_info['type']}", ""), + discovery_info["properties"]["id"], + ) + + async def async_step_ssdp(self, discovery_info: DiscoveryInfoType) -> FlowResult: + """Handle Nanoleaf SSDP discovery.""" + _LOGGER.debug("SSDP discovered: %s", discovery_info) + return await self._async_discovery_handler( + discovery_info["_host"], + discovery_info["nl-devicename"], + discovery_info["nl-deviceid"], + ) + + async def _async_discovery_handler( + self, host: str, name: str, device_id: str ) -> FlowResult: """Handle Nanoleaf discovery.""" - host = discovery_info["host"] # The name is unique and printed on the device and cannot be changed. - name = discovery_info["name"].replace(f".{discovery_info['type']}", "") await self.async_set_unique_id(name) self._abort_if_unique_id_configured({CONF_HOST: host}) # Import from discovery integration - self.device_id = discovery_info["properties"]["id"] + self.device_id = device_id self.discovery_conf = cast( dict, await self.hass.async_add_executor_job( diff --git a/homeassistant/components/nanoleaf/manifest.json b/homeassistant/components/nanoleaf/manifest.json index 133257dc7fe..c527127f6e8 100644 --- a/homeassistant/components/nanoleaf/manifest.json +++ b/homeassistant/components/nanoleaf/manifest.json @@ -10,6 +10,20 @@ "NL*" ] }, + "ssdp": [ + { + "st": "Nanoleaf_aurora:light" + }, + { + "st": "nanoleaf:nl29" + }, + { + "st": "nanoleaf:nl42" + }, + { + "st": "nanoleaf:nl52" + } + ], "codeowners": ["@milanmeu"], "iot_class": "local_polling" } \ No newline at end of file diff --git a/homeassistant/generated/ssdp.py b/homeassistant/generated/ssdp.py index b058f972229..6d15477bf02 100644 --- a/homeassistant/generated/ssdp.py +++ b/homeassistant/generated/ssdp.py @@ -171,6 +171,20 @@ SSDP = { "manufacturer": "konnected.io" } ], + "nanoleaf": [ + { + "st": "Nanoleaf_aurora:light" + }, + { + "st": "nanoleaf:nl29" + }, + { + "st": "nanoleaf:nl42" + }, + { + "st": "nanoleaf:nl52" + } + ], "netgear": [ { "deviceType": "urn:schemas-upnp-org:device:InternetGatewayDevice:1", diff --git a/tests/components/nanoleaf/test_config_flow.py b/tests/components/nanoleaf/test_config_flow.py index 8f62830b219..ba0eff4abe3 100644 --- a/tests/components/nanoleaf/test_config_flow.py +++ b/tests/components/nanoleaf/test_config_flow.py @@ -74,10 +74,7 @@ async def test_user_unavailable_user_step_link_step(hass: HomeAssistant) -> None "homeassistant.components.nanoleaf.config_flow.Nanoleaf.authorize", side_effect=Unavailable, ): - result3 = await hass.config_entries.flow.async_configure( - result["flow_id"], - {}, - ) + result3 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result3["type"] == "abort" assert result3["reason"] == "cannot_connect" @@ -115,10 +112,7 @@ async def test_user_error_setup_finish( "homeassistant.components.nanoleaf.config_flow.Nanoleaf.get_info", side_effect=error, ): - result3 = await hass.config_entries.flow.async_configure( - result["flow_id"], - {}, - ) + result3 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result3["type"] == "abort" assert result3["reason"] == reason @@ -151,9 +145,7 @@ async def test_user_not_authorizing_new_tokens_user_step_link_step( assert result2["errors"] is None assert result2["step_id"] == "link" - result3 = await hass.config_entries.flow.async_configure( - result["flow_id"], - ) + result3 = await hass.config_entries.flow.async_configure(result["flow_id"]) assert result3["type"] == "form" assert result3["errors"] is None assert result3["step_id"] == "link" @@ -165,10 +157,7 @@ async def test_user_not_authorizing_new_tokens_user_step_link_step( mock_nanoleaf.return_value.authorize.side_effect = None - result5 = await hass.config_entries.flow.async_configure( - result["flow_id"], - {}, - ) + result5 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result5["type"] == "create_entry" assert result5["title"] == TEST_NAME assert result5["data"] == { @@ -213,20 +202,14 @@ async def test_user_exception_user_step(hass: HomeAssistant) -> None: mock_nanoleaf.return_value.authorize.side_effect = Exception() - result4 = await hass.config_entries.flow.async_configure( - result["flow_id"], - {}, - ) + result4 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result4["type"] == "form" assert result4["step_id"] == "link" assert result4["errors"] == {"base": "unknown"} mock_nanoleaf.return_value.authorize.side_effect = None mock_nanoleaf.return_value.get_info.side_effect = Exception() - result5 = await hass.config_entries.flow.async_configure( - result["flow_id"], - {}, - ) + result5 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result5["type"] == "abort" assert result5["reason"] == "unknown" @@ -307,10 +290,7 @@ async def test_reauth(hass: HomeAssistant) -> None: assert result["type"] == "form" assert result["step_id"] == "link" - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - {}, - ) + result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result2["type"] == "abort" assert result2["reason"] == "reauth_successful" @@ -460,3 +440,42 @@ async def test_import_discovery_integration( await hass.async_block_till_done() assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_ssdp_discovery(hass: HomeAssistant) -> None: + """Test SSDP discovery.""" + with patch( + "homeassistant.components.nanoleaf.config_flow.load_json", + return_value={}, + ), patch( + "homeassistant.components.nanoleaf.config_flow.Nanoleaf", + return_value=_mock_nanoleaf(TEST_HOST, TEST_TOKEN), + ), patch( + "homeassistant.components.nanoleaf.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_SSDP}, + data={ + "_host": TEST_HOST, + "nl-devicename": TEST_NAME, + "nl-deviceid": TEST_DEVICE_ID, + }, + ) + + assert result["type"] == "form" + assert result["errors"] is None + assert result["step_id"] == "link" + + result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + assert result2["type"] == "create_entry" + assert result2["title"] == TEST_NAME + assert result2["data"] == { + CONF_HOST: TEST_HOST, + CONF_TOKEN: TEST_TOKEN, + } + + await hass.async_block_till_done() + assert len(mock_setup_entry.mock_calls) == 1