diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 558b0fe4205..0ea91d10b19 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -4,8 +4,8 @@ import voluptuous as vol from homeassistant.const import EVENT_HOMEASSISTANT_STOP from .config_flow import get_master_gateway -from .const import CONF_BRIDGEID, CONF_MASTER_GATEWAY, DOMAIN -from .gateway import DeconzGateway +from .const import CONF_BRIDGEID, CONF_MASTER_GATEWAY, CONF_UUID, DOMAIN +from .gateway import DeconzGateway, get_gateway_from_config_entry from .services import async_setup_services, async_unload_services CONFIG_SCHEMA = vol.Schema( @@ -39,6 +39,9 @@ async def async_setup_entry(hass, config_entry): await gateway.async_update_device_registry() + if CONF_UUID not in config_entry.data: + await async_add_uuid_to_config_entry(hass, config_entry) + await async_setup_services(hass) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown) @@ -68,11 +71,14 @@ async def async_update_master_gateway(hass, config_entry): Makes sure there is always one master available. """ master = not get_master_gateway(hass) - - old_options = dict(config_entry.options) - - new_options = {CONF_MASTER_GATEWAY: master} - - options = {**old_options, **new_options} + options = {**config_entry.options, CONF_MASTER_GATEWAY: master} hass.config_entries.async_update_entry(config_entry, options=options) + + +async def async_add_uuid_to_config_entry(hass, config_entry): + """Add UUID to config entry to help discovery identify entries.""" + gateway = get_gateway_from_config_entry(hass, config_entry) + config = {**config_entry.data, CONF_UUID: gateway.api.config.uuid} + + hass.config_entries.async_update_entry(config_entry, data=config) diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index c63b1721393..488d48bb740 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -5,7 +5,7 @@ import async_timeout import voluptuous as vol from pydeconz.errors import ResponseError, RequestError -from pydeconz.utils import async_discovery, async_get_api_key, async_get_bridgeid +from pydeconz.utils import async_discovery, async_get_api_key, async_get_gateway_config from homeassistant import config_entries from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT @@ -16,6 +16,7 @@ from .const import ( CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID, + CONF_UUID, DEFAULT_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_DECONZ_GROUPS, DEFAULT_PORT, @@ -144,9 +145,11 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): try: with async_timeout.timeout(10): - self.deconz_config[CONF_BRIDGEID] = await async_get_bridgeid( + gateway_config = await async_get_gateway_config( session, **self.deconz_config ) + self.deconz_config[CONF_BRIDGEID] = gateway_config.bridgeid + self.deconz_config[CONF_UUID] = gateway_config.uuid except asyncio.TimeoutError: return self.async_abort(reason="no_bridges") @@ -172,14 +175,10 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): return self.async_abort(reason="not_deconz_bridge") uuid = discovery_info[ATTR_UUID].replace("uuid:", "") - gateways = { - gateway.api.config.uuid: gateway - for gateway in self.hass.data.get(DOMAIN, {}).values() - } - if uuid in gateways: - entry = gateways[uuid].config_entry - return await self._update_entry(entry, discovery_info[CONF_HOST]) + for entry in self.hass.config_entries.async_entries(DOMAIN): + if uuid == entry.data.get(CONF_UUID): + return await self._update_entry(entry, discovery_info[CONF_HOST]) bridgeid = discovery_info[ATTR_SERIAL] if any( diff --git a/homeassistant/components/deconz/const.py b/homeassistant/components/deconz/const.py index 62879a82724..ad23a564272 100644 --- a/homeassistant/components/deconz/const.py +++ b/homeassistant/components/deconz/const.py @@ -5,13 +5,15 @@ _LOGGER = logging.getLogger(__package__) DOMAIN = "deconz" +CONF_BRIDGEID = "bridgeid" +CONF_UUID = "uuid" + DEFAULT_PORT = 80 DEFAULT_ALLOW_CLIP_SENSOR = False DEFAULT_ALLOW_DECONZ_GROUPS = True CONF_ALLOW_CLIP_SENSOR = "allow_clip_sensor" CONF_ALLOW_DECONZ_GROUPS = "allow_deconz_groups" -CONF_BRIDGEID = "bridgeid" CONF_MASTER_GATEWAY = "master" SUPPORTED_PLATFORMS = [ diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index fe8f49d260a..4aec29008de 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/components/deconz", "requirements": [ - "pydeconz==62" + "pydeconz==63" ], "ssdp": { "manufacturer": [ diff --git a/requirements_all.txt b/requirements_all.txt index 2f8ae35125d..73ececb0517 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1129,7 +1129,7 @@ pydaikin==1.6.1 pydanfossair==0.1.0 # homeassistant.components.deconz -pydeconz==62 +pydeconz==63 # homeassistant.components.delijn pydelijn==0.5.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c92b16b78fe..6f542147363 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -294,7 +294,7 @@ pyblackbird==0.5 pychromecast==4.0.1 # homeassistant.components.deconz -pydeconz==62 +pydeconz==63 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index d7071d6daef..4d8d3a31258 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -209,22 +209,25 @@ async def test_bridge_discovery_update_existing_entry(hass): """Test if a discovered bridge has already been configured.""" entry = MockConfigEntry( domain=config_flow.DOMAIN, - data={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_BRIDGEID: "id"}, + data={ + config_flow.CONF_HOST: "1.2.3.4", + config_flow.CONF_BRIDGEID: "123ABC", + config_flow.CONF_UUID: "456DEF", + }, ) entry.add_to_hass(hass) gateway = Mock() gateway.config_entry = entry - gateway.api.config.uuid = "1234" - hass.data[config_flow.DOMAIN] = {"id": gateway} + hass.data[config_flow.DOMAIN] = {"123ABC": gateway} result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, data={ config_flow.CONF_HOST: "mock-deconz", - ATTR_SERIAL: "id", + ATTR_SERIAL: "123ABC", ATTR_MANUFACTURERURL: config_flow.DECONZ_MANUFACTURERURL, - config_flow.ATTR_UUID: "uuid:1234", + config_flow.ATTR_UUID: "uuid:456DEF", }, context={"source": "ssdp"}, ) @@ -238,7 +241,7 @@ async def test_create_entry(hass, aioclient_mock): """Test that _create_entry work and that bridgeid can be requested.""" aioclient_mock.get( "http://1.2.3.4:80/api/1234567890ABCDEF/config", - json={"bridgeid": "id"}, + json={"bridgeid": "123ABC", "uuid": "456DEF"}, headers={"content-type": "application/json"}, ) @@ -253,12 +256,13 @@ async def test_create_entry(hass, aioclient_mock): result = await flow._create_entry() assert result["type"] == "create_entry" - assert result["title"] == "deCONZ-id" + assert result["title"] == "deCONZ-123ABC" assert result["data"] == { - config_flow.CONF_BRIDGEID: "id", + config_flow.CONF_BRIDGEID: "123ABC", config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80, config_flow.CONF_API_KEY: "1234567890ABCDEF", + config_flow.CONF_UUID: "456DEF", } @@ -273,7 +277,7 @@ async def test_create_entry_timeout(hass, aioclient_mock): } with patch( - "homeassistant.components.deconz.config_flow.async_get_bridgeid", + "homeassistant.components.deconz.config_flow.async_get_gateway_config", side_effect=asyncio.TimeoutError, ): result = await flow._create_entry() diff --git a/tests/components/deconz/test_gateway.py b/tests/components/deconz/test_gateway.py index 25a1cd465c5..b98681b6fc9 100644 --- a/tests/components/deconz/test_gateway.py +++ b/tests/components/deconz/test_gateway.py @@ -20,6 +20,7 @@ ENTRY_CONFIG = { deconz.config_flow.CONF_BRIDGEID: BRIDGEID, deconz.config_flow.CONF_HOST: "1.2.3.4", deconz.config_flow.CONF_PORT: 80, + deconz.config_flow.CONF_UUID: "456DEF", } DECONZ_CONFIG = { @@ -147,7 +148,7 @@ async def test_update_address(hass): deconz.config_flow.CONF_PORT: 80, ssdp.ATTR_SERIAL: BRIDGEID, ssdp.ATTR_MANUFACTURERURL: deconz.config_flow.DECONZ_MANUFACTURERURL, - deconz.config_flow.ATTR_UUID: "uuid:1234", + deconz.config_flow.ATTR_UUID: "uuid:456DEF", }, context={"source": "ssdp"}, ) diff --git a/tests/components/deconz/test_init.py b/tests/components/deconz/test_init.py index 7d630498cde..986e01a1599 100644 --- a/tests/components/deconz/test_init.py +++ b/tests/components/deconz/test_init.py @@ -1,33 +1,34 @@ """Test deCONZ component setup process.""" -from unittest.mock import Mock, patch - import asyncio + +from asynctest import Mock, patch + import pytest from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.components import deconz -from tests.common import mock_coro, MockConfigEntry +from tests.common import MockConfigEntry ENTRY1_HOST = "1.2.3.4" ENTRY1_PORT = 80 ENTRY1_API_KEY = "1234567890ABCDEF" ENTRY1_BRIDGEID = "12345ABC" +ENTRY1_UUID = "456DEF" ENTRY2_HOST = "2.3.4.5" ENTRY2_PORT = 80 ENTRY2_API_KEY = "1234567890ABCDEF" ENTRY2_BRIDGEID = "23456DEF" +ENTRY2_UUID = "789ACE" async def setup_entry(hass, entry): """Test that setup entry works.""" with patch.object( - deconz.DeconzGateway, "async_setup", return_value=mock_coro(True) + deconz.DeconzGateway, "async_setup", return_value=True ), patch.object( - deconz.DeconzGateway, - "async_update_device_registry", - return_value=mock_coro(True), + deconz.DeconzGateway, "async_update_device_registry", return_value=True ): assert await deconz.async_setup_entry(hass, entry) is True @@ -67,6 +68,7 @@ async def test_setup_entry_successful(hass): deconz.config_flow.CONF_PORT: ENTRY1_PORT, deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, + deconz.CONF_UUID: ENTRY1_UUID, }, ) entry.add_to_hass(hass) @@ -86,6 +88,7 @@ async def test_setup_entry_multiple_gateways(hass): deconz.config_flow.CONF_PORT: ENTRY1_PORT, deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, + deconz.CONF_UUID: ENTRY1_UUID, }, ) entry.add_to_hass(hass) @@ -97,6 +100,7 @@ async def test_setup_entry_multiple_gateways(hass): deconz.config_flow.CONF_PORT: ENTRY2_PORT, deconz.config_flow.CONF_API_KEY: ENTRY2_API_KEY, deconz.CONF_BRIDGEID: ENTRY2_BRIDGEID, + deconz.CONF_UUID: ENTRY2_UUID, }, ) entry2.add_to_hass(hass) @@ -119,15 +123,14 @@ async def test_unload_entry(hass): deconz.config_flow.CONF_PORT: ENTRY1_PORT, deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, + deconz.CONF_UUID: ENTRY1_UUID, }, ) entry.add_to_hass(hass) await setup_entry(hass, entry) - with patch.object( - deconz.DeconzGateway, "async_reset", return_value=mock_coro(True) - ): + with patch.object(deconz.DeconzGateway, "async_reset", return_value=True): assert await deconz.async_unload_entry(hass, entry) assert not hass.data[deconz.DOMAIN] @@ -142,6 +145,7 @@ async def test_unload_entry_multiple_gateways(hass): deconz.config_flow.CONF_PORT: ENTRY1_PORT, deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, + deconz.CONF_UUID: ENTRY1_UUID, }, ) entry.add_to_hass(hass) @@ -153,6 +157,7 @@ async def test_unload_entry_multiple_gateways(hass): deconz.config_flow.CONF_PORT: ENTRY2_PORT, deconz.config_flow.CONF_API_KEY: ENTRY2_API_KEY, deconz.CONF_BRIDGEID: ENTRY2_BRIDGEID, + deconz.CONF_UUID: ENTRY2_UUID, }, ) entry2.add_to_hass(hass) @@ -160,9 +165,7 @@ async def test_unload_entry_multiple_gateways(hass): await setup_entry(hass, entry) await setup_entry(hass, entry2) - with patch.object( - deconz.DeconzGateway, "async_reset", return_value=mock_coro(True) - ): + with patch.object(deconz.DeconzGateway, "async_reset", return_value=True): assert await deconz.async_unload_entry(hass, entry) assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN]