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 0a3deeef33bfb7..883958226d8d09 100644 --- a/homeassistant/components/discovery/__init__.py +++ b/homeassistant/components/discovery/__init__.py @@ -22,7 +22,6 @@ 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 @@ 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 35e89eb2b09fa3..f36a2303b6d7c1 100644 --- a/homeassistant/components/freebox/__init__.py +++ b/homeassistant/components/freebox/__init__.py @@ -25,26 +25,20 @@ 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 49354f16705fa2..f4fde23473f149 100644 --- a/homeassistant/components/freebox/config_flow.py +++ b/homeassistant/components/freebox/config_flow.py @@ -105,3 +105,9 @@ async def async_step_link(self, user_input=None): 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 ad935c47cc47e5..5f3aace94652e3 100644 --- a/tests/components/freebox/test_config_flow.py +++ b/tests/components/freebox/test_config_flow.py @@ -10,7 +10,7 @@ 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 @@ 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(