From 4517f0d59ab20735c3cae760803c117241c044bb Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 18 Mar 2020 11:10:40 +0100 Subject: [PATCH] Handle unique WLED device using zeroconf properties (#32897) --- homeassistant/components/wled/config_flow.py | 37 +++++++++++--------- tests/components/wled/test_config_flow.py | 30 +++++++++++++--- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/wled/config_flow.py b/homeassistant/components/wled/config_flow.py index dbcd55a7b17..da1193b1a01 100644 --- a/homeassistant/components/wled/config_flow.py +++ b/homeassistant/components/wled/config_flow.py @@ -44,7 +44,12 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN): # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 self.context.update( - {CONF_HOST: host, CONF_NAME: name, "title_placeholders": {"name": name}} + { + CONF_HOST: host, + CONF_NAME: name, + CONF_MAC: user_input["properties"].get(CONF_MAC), + "title_placeholders": {"name": name}, + } ) # Prepare configuration flow @@ -72,23 +77,22 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN): if source == SOURCE_ZEROCONF: # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 user_input[CONF_HOST] = self.context.get(CONF_HOST) + user_input[CONF_MAC] = self.context.get(CONF_MAC) - errors = {} - session = async_get_clientsession(self.hass) - wled = WLED(user_input[CONF_HOST], session=session) - - try: - device = await wled.update() - except WLEDConnectionError: - if source == SOURCE_ZEROCONF: - return self.async_abort(reason="connection_error") - errors["base"] = "connection_error" - return self._show_setup_form(errors) + if user_input.get(CONF_MAC) is None or not prepare: + session = async_get_clientsession(self.hass) + wled = WLED(user_input[CONF_HOST], session=session) + try: + device = await wled.update() + except WLEDConnectionError: + if source == SOURCE_ZEROCONF: + return self.async_abort(reason="connection_error") + return self._show_setup_form({"base": "connection_error"}) + user_input[CONF_MAC] = device.info.mac_address # Check if already configured - mac_address = device.info.mac_address - await self.async_set_unique_id(device.info.mac_address) - self._abort_if_unique_id_configured() + await self.async_set_unique_id(user_input[CONF_MAC]) + self._abort_if_unique_id_configured(updates={CONF_HOST: user_input[CONF_HOST]}) title = user_input[CONF_HOST] if source == SOURCE_ZEROCONF: @@ -99,7 +103,8 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN): return await self.async_step_zeroconf_confirm() return self.async_create_entry( - title=title, data={CONF_HOST: user_input[CONF_HOST], CONF_MAC: mac_address} + title=title, + data={CONF_HOST: user_input[CONF_HOST], CONF_MAC: user_input[CONF_MAC]}, ) def _show_setup_form(self, errors: Optional[Dict] = None) -> Dict[str, Any]: diff --git a/tests/components/wled/test_config_flow.py b/tests/components/wled/test_config_flow.py index 4a43706dde2..521a7b67a46 100644 --- a/tests/components/wled/test_config_flow.py +++ b/tests/components/wled/test_config_flow.py @@ -48,7 +48,9 @@ async def test_show_zerconf_form( flow = config_flow.WLEDFlowHandler() flow.hass = hass flow.context = {"source": SOURCE_ZEROCONF} - result = await flow.async_step_zeroconf({"hostname": "example.local."}) + result = await flow.async_step_zeroconf( + {"hostname": "example.local.", "properties": {}} + ) assert flow.context[CONF_HOST] == "example.local" assert flow.context[CONF_NAME] == "example" @@ -83,7 +85,7 @@ async def test_zeroconf_connection_error( result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, context={"source": SOURCE_ZEROCONF}, - data={"hostname": "example.local."}, + data={"hostname": "example.local.", "properties": {}}, ) assert result["reason"] == "connection_error" @@ -103,7 +105,7 @@ async def test_zeroconf_confirm_connection_error( CONF_HOST: "example.com", CONF_NAME: "test", }, - data={"hostname": "example.com."}, + data={"hostname": "example.com.", "properties": {}}, ) assert result["reason"] == "connection_error" @@ -147,7 +149,23 @@ async def test_zeroconf_device_exists_abort( result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, context={"source": SOURCE_ZEROCONF}, - data={"hostname": "example.local."}, + data={"hostname": "example.local.", "properties": {}}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + + +async def test_zeroconf_with_mac_device_exists_abort( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test we abort zeroconf flow if WLED device already configured.""" + await init_integration(hass, aioclient_mock) + + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, + context={"source": SOURCE_ZEROCONF}, + data={"hostname": "example.local.", "properties": {CONF_MAC: "aabbccddeeff"}}, ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT @@ -194,7 +212,9 @@ async def test_full_zeroconf_flow_implementation( flow = config_flow.WLEDFlowHandler() flow.hass = hass flow.context = {"source": SOURCE_ZEROCONF} - result = await flow.async_step_zeroconf({"hostname": "example.local."}) + result = await flow.async_step_zeroconf( + {"hostname": "example.local.", "properties": {}} + ) assert flow.context[CONF_HOST] == "example.local" assert flow.context[CONF_NAME] == "example"