From 125206adbf85cf49bf72336db658f7776b924fe5 Mon Sep 17 00:00:00 2001 From: Quentame Date: Thu, 25 Feb 2021 16:50:58 +0100 Subject: [PATCH] Add zeroconf discovery to Freebox (#47045) * Add zeroconf discovery to Freebox - remove deprecated discovery - tried with SSDP too but the presentation URL is not the same (*.fbxos.fr for zeroconf, http://mafreebox.freebox.fr/ for SSDP) - so config entry unique_id should be the MAC (included into SSDP, but not zeroconf, can be retrieve from `fbx.system.get_config()`) - DHCP discovery might be added in the future too * host and port are required on zeroconf * cleanup in other PR --- .../components/discovery/__init__.py | 2 -- homeassistant/components/freebox/__init__.py | 22 +++++-------- .../components/freebox/config_flow.py | 6 ++++ tests/components/freebox/test_config_flow.py | 32 ++++++++++++++++++- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/discovery/__init__.py b/homeassistant/components/discovery/__init__.py index 0a3deeef33b..883958226d8 100644 --- a/homeassistant/components/discovery/__init__.py +++ b/homeassistant/components/discovery/__init__.py @@ -22,7 +22,6 @@ SERVICE_APPLE_TV = "apple_tv" SERVICE_DAIKIN = "daikin" SERVICE_DLNA_DMR = "dlna_dmr" SERVICE_ENIGMA2 = "enigma2" -SERVICE_FREEBOX = "freebox" SERVICE_HASS_IOS_APP = "hass_ios" SERVICE_HASSIO = "hassio" SERVICE_HEOS = "heos" @@ -67,7 +66,6 @@ MIGRATED_SERVICE_HANDLERS = [ SERVICE_DAIKIN, "denonavr", "esphome", - SERVICE_FREEBOX, "google_cast", SERVICE_HASS_IOS_APP, SERVICE_HASSIO, diff --git a/homeassistant/components/freebox/__init__.py b/homeassistant/components/freebox/__init__.py index 35e89eb2b09..f36a2303b6d 100644 --- a/homeassistant/components/freebox/__init__.py +++ b/homeassistant/components/freebox/__init__.py @@ -25,26 +25,20 @@ CONFIG_SCHEMA = vol.Schema( async def async_setup(hass, config): - """Set up the Freebox component.""" - conf = config.get(DOMAIN) - - if conf is None: - return True - - for freebox_conf in conf: - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=freebox_conf, + """Set up the Freebox integration.""" + if DOMAIN in config: + for entry_config in config[DOMAIN]: + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=entry_config + ) ) - ) return True async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): - """Set up Freebox component.""" + """Set up Freebox entry.""" router = FreeboxRouter(hass, entry) await router.setup() diff --git a/homeassistant/components/freebox/config_flow.py b/homeassistant/components/freebox/config_flow.py index 49354f16705..f4fde23473f 100644 --- a/homeassistant/components/freebox/config_flow.py +++ b/homeassistant/components/freebox/config_flow.py @@ -105,3 +105,9 @@ class FreeboxFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_import(self, user_input=None): """Import a config entry.""" return await self.async_step_user(user_input) + + async def async_step_zeroconf(self, discovery_info: dict): + """Initialize flow from zeroconf.""" + host = discovery_info["properties"]["api_domain"] + port = discovery_info["properties"]["https_port"] + return await self.async_step_user({CONF_HOST: host, CONF_PORT: port}) diff --git a/tests/components/freebox/test_config_flow.py b/tests/components/freebox/test_config_flow.py index ad935c47cc4..5f3aace9465 100644 --- a/tests/components/freebox/test_config_flow.py +++ b/tests/components/freebox/test_config_flow.py @@ -10,7 +10,7 @@ import pytest from homeassistant import data_entry_flow from homeassistant.components.freebox.const import DOMAIN -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, SOURCE_ZEROCONF from homeassistant.const import CONF_HOST, CONF_PORT from tests.common import MockConfigEntry @@ -18,6 +18,25 @@ from tests.common import MockConfigEntry HOST = "myrouter.freeboxos.fr" PORT = 1234 +MOCK_ZEROCONF_DATA = { + "host": "192.168.0.254", + "port": 80, + "hostname": "Freebox-Server.local.", + "type": "_fbx-api._tcp.local.", + "name": "Freebox Server._fbx-api._tcp.local.", + "properties": { + "api_version": "8.0", + "device_type": "FreeboxServer1,2", + "api_base_url": "/api/", + "uid": "b15ab20debb399f95001a9ca207d2777", + "https_available": "1", + "https_port": f"{PORT}", + "box_model": "fbxgw-r2/full", + "box_model_name": "Freebox Server (r2)", + "api_domain": HOST, + }, +} + @pytest.fixture(name="connect") def mock_controller_connect(): @@ -66,6 +85,17 @@ async def test_import(hass): assert result["step_id"] == "link" +async def test_zeroconf(hass): + """Test zeroconf step.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_ZEROCONF}, + data=MOCK_ZEROCONF_DATA, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "link" + + async def test_link(hass, connect): """Test linking.""" result = await hass.config_entries.flow.async_init(