diff --git a/homeassistant/components/overkiz/config_flow.py b/homeassistant/components/overkiz/config_flow.py index 467bb9f007b..57e5ae12749 100644 --- a/homeassistant/components/overkiz/config_flow.py +++ b/homeassistant/components/overkiz/config_flow.py @@ -15,7 +15,7 @@ from pyoverkiz.models import obfuscate_id import voluptuous as vol from homeassistant import config_entries -from homeassistant.components import dhcp +from homeassistant.components import dhcp, zeroconf from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -97,3 +97,19 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self._abort_if_unique_id_configured() return await self.async_step_user() + + async def async_step_zeroconf( + self, discovery_info: zeroconf.ZeroconfServiceInfo + ) -> FlowResult: + """Handle ZeroConf discovery.""" + + # abort if we already have exactly this bridge id/host + properties = discovery_info.properties + gateway_id = properties["gateway_pin"] + + LOGGER.debug("ZeroConf discovery detected gateway %s", obfuscate_id(gateway_id)) + + await self.async_set_unique_id(gateway_id) + self._abort_if_unique_id_configured() + + return await self.async_step_user() diff --git a/homeassistant/components/overkiz/manifest.json b/homeassistant/components/overkiz/manifest.json index f2cffffc484..0783d37beaf 100644 --- a/homeassistant/components/overkiz/manifest.json +++ b/homeassistant/components/overkiz/manifest.json @@ -6,6 +6,12 @@ "requirements": [ "pyoverkiz==1.2.0" ], + "zeroconf": [ + { + "type": "_kizbox._tcp.local.", + "name": "gateway*" + } + ], "dhcp": [ { "hostname": "gateway*", diff --git a/homeassistant/generated/zeroconf.py b/homeassistant/generated/zeroconf.py index 413d4371192..da48577a146 100644 --- a/homeassistant/generated/zeroconf.py +++ b/homeassistant/generated/zeroconf.py @@ -205,6 +205,10 @@ ZEROCONF = { } ], "_kizbox._tcp.local.": [ + { + "domain": "overkiz", + "name": "gateway*" + }, { "domain": "somfy", "name": "gateway*" diff --git a/tests/components/overkiz/test_config_flow.py b/tests/components/overkiz/test_config_flow.py index 29534f46365..b211d93bcfe 100644 --- a/tests/components/overkiz/test_config_flow.py +++ b/tests/components/overkiz/test_config_flow.py @@ -14,6 +14,7 @@ import pytest from homeassistant import config_entries, data_entry_flow from homeassistant.components import dhcp from homeassistant.components.overkiz.const import DOMAIN +from homeassistant.components.zeroconf import ZeroconfServiceInfo from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry @@ -29,6 +30,19 @@ TEST_GATEWAY_ID2 = "4321-5678-9123" MOCK_GATEWAY_RESPONSE = [Mock(id=TEST_GATEWAY_ID)] +FAKE_ZERO_CONF_INFO = ZeroconfServiceInfo( + host="192.168.0.51", + port=443, + hostname=f"gateway-{TEST_GATEWAY_ID}.local.", + type="_kizbox._tcp.local.", + name=f"gateway-{TEST_GATEWAY_ID}._kizbox._tcp.local.", + properties={ + "api_version": "1", + "gateway_pin": TEST_GATEWAY_ID, + "fw_version": "2021.5.4-29", + }, +) + async def test_form(hass: HomeAssistant) -> None: """Test we get the form.""" @@ -204,3 +218,54 @@ async def test_dhcp_flow_already_configured(hass: HomeAssistant) -> None: assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured" + + +async def test_zeroconf_flow(hass): + """Test that zeroconf discovery for new bridge works.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + data=FAKE_ZERO_CONF_INFO, + context={"source": config_entries.SOURCE_ZEROCONF}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == config_entries.SOURCE_USER + + with patch("pyoverkiz.client.OverkizClient.login", return_value=True), patch( + "pyoverkiz.client.OverkizClient.get_gateways", return_value=None + ), patch( + "homeassistant.components.overkiz.async_setup_entry", return_value=True + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"username": TEST_EMAIL, "password": TEST_PASSWORD, "hub": TEST_HUB}, + ) + + assert result2["type"] == "create_entry" + assert result2["title"] == TEST_EMAIL + assert result2["data"] == { + "username": TEST_EMAIL, + "password": TEST_PASSWORD, + "hub": TEST_HUB, + } + + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_zeroconf_flow_already_configured(hass): + """Test that zeroconf doesn't setup already configured gateways.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + unique_id=TEST_GATEWAY_ID, + data={"username": TEST_EMAIL, "password": TEST_PASSWORD, "hub": TEST_HUB}, + ) + config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + data=FAKE_ZERO_CONF_INFO, + context={"source": config_entries.SOURCE_ZEROCONF}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured"