Use config entry unique id for deCONZ (#30122)

* Use config entry unique id

* Clean up

* Backwards compatiblity note

* Fix some of Balloobs comments

* Bump dependency to v66

* Black somehow missed config flow tests...

* Move set unique ID til after possibility to update existing entry
This commit is contained in:
Robert Svensson 2020-01-03 11:50:53 +01:00 committed by Paulus Schoutsen
parent c130e81638
commit 0a4f3ec1ec
12 changed files with 136 additions and 226 deletions

View File

@ -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, CONF_UUID, DOMAIN
from .gateway import DeconzGateway, get_gateway_from_config_entry
from .const import CONF_MASTER_GATEWAY, DOMAIN
from .gateway import DeconzGateway
from .services import async_setup_services, async_unload_services
CONFIG_SCHEMA = vol.Schema(
@ -35,13 +35,16 @@ async def async_setup_entry(hass, config_entry):
if not await gateway.async_setup():
return False
hass.data[DOMAIN][gateway.bridgeid] = gateway
# 0.104 introduced config entry unique id, this makes upgrading possible
if config_entry.unique_id is None:
hass.config_entries.async_update_entry(
config_entry, unique_id=gateway.api.config.bridgeid
)
hass.data[DOMAIN][config_entry.unique_id] = gateway
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)
@ -51,7 +54,7 @@ async def async_setup_entry(hass, config_entry):
async def async_unload_entry(hass, config_entry):
"""Unload deCONZ config entry."""
gateway = hass.data[DOMAIN].pop(config_entry.data[CONF_BRIDGEID])
gateway = hass.data[DOMAIN].pop(config_entry.unique_id)
if not hass.data[DOMAIN]:
await async_unload_services(hass)
@ -74,11 +77,3 @@ async def async_update_master_gateway(hass, config_entry):
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)

View File

@ -4,7 +4,12 @@ from urllib.parse import urlparse
import async_timeout
from pydeconz.errors import RequestError, ResponseError
from pydeconz.utils import async_discovery, async_get_api_key, async_get_gateway_config
from pydeconz.utils import (
async_discovery,
async_get_api_key,
async_get_bridge_id,
normalize_bridge_id,
)
import voluptuous as vol
from homeassistant import config_entries
@ -14,11 +19,9 @@ from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
from .const import (
_LOGGER,
CONF_ALLOW_CLIP_SENSOR,
CONF_ALLOW_DECONZ_GROUPS,
CONF_BRIDGEID,
CONF_UUID,
DEFAULT_ALLOW_CLIP_SENSOR,
DEFAULT_ALLOW_DECONZ_GROUPS,
DEFAULT_PORT,
@ -29,15 +32,6 @@ DECONZ_MANUFACTURERURL = "http://www.dresden-elektronik.de"
CONF_SERIAL = "serial"
@callback
def configured_gateways(hass):
"""Return a set of all configured gateways."""
return {
entry.data[CONF_BRIDGEID]: entry
for entry in hass.config_entries.async_entries(DOMAIN)
}
@callback
def get_master_gateway(hass):
"""Return the gateway which is marked as master."""
@ -62,6 +56,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
def __init__(self):
"""Initialize the deCONZ config flow."""
self.bridge_id = None
self.bridges = []
self.deconz_config = {}
@ -79,7 +74,11 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if user_input is not None:
for bridge in self.bridges:
if bridge[CONF_HOST] == user_input[CONF_HOST]:
self.deconz_config = bridge
self.bridge_id = bridge[CONF_BRIDGEID]
self.deconz_config = {
CONF_HOST: bridge[CONF_HOST],
CONF_PORT: bridge[CONF_PORT],
}
return await self.async_step_link()
self.deconz_config = user_input
@ -95,8 +94,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self.bridges = []
if len(self.bridges) == 1:
self.deconz_config = self.bridges[0]
return await self.async_step_link()
return await self.async_step_user(self.bridges[0])
if len(self.bridges) > 1:
hosts = []
@ -141,23 +139,21 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def _create_entry(self):
"""Create entry for gateway."""
if CONF_BRIDGEID not in self.deconz_config:
if not self.bridge_id:
session = aiohttp_client.async_get_clientsession(self.hass)
try:
with async_timeout.timeout(10):
gateway_config = await async_get_gateway_config(
self.bridge_id = await async_get_bridge_id(
session, **self.deconz_config
)
self.deconz_config[CONF_BRIDGEID] = gateway_config.bridgeid
self.deconz_config[CONF_UUID] = gateway_config.uuid
await self.async_set_unique_id(self.bridge_id)
self._abort_if_unique_id_configured()
except asyncio.TimeoutError:
return self.async_abort(reason="no_bridges")
return self.async_create_entry(
title="deCONZ-" + self.deconz_config[CONF_BRIDGEID], data=self.deconz_config
)
return self.async_create_entry(title=self.bridge_id, data=self.deconz_config)
def _update_entry(self, entry, host, port, api_key=None):
"""Update existing entry."""
@ -182,27 +178,17 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if discovery_info[ssdp.ATTR_UPNP_MANUFACTURER_URL] != DECONZ_MANUFACTURERURL:
return self.async_abort(reason="not_deconz_bridge")
uuid = discovery_info[ssdp.ATTR_UPNP_UDN].replace("uuid:", "")
_LOGGER.debug("deCONZ gateway discovered (%s)", uuid)
self.bridge_id = normalize_bridge_id(discovery_info[ssdp.ATTR_UPNP_SERIAL])
parsed_url = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION])
for entry in self.hass.config_entries.async_entries(DOMAIN):
if uuid == entry.data.get(CONF_UUID):
if self.bridge_id == entry.unique_id:
if entry.source == "hassio":
return self.async_abort(reason="already_configured")
return self._update_entry(entry, parsed_url.hostname, parsed_url.port)
bridgeid = discovery_info[ssdp.ATTR_UPNP_SERIAL]
if any(
bridgeid == flow["context"][CONF_BRIDGEID]
for flow in self._async_in_progress()
):
return self.async_abort(reason="already_in_progress")
await self.async_set_unique_id(self.bridge_id)
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
self.context[CONF_BRIDGEID] = bridgeid
self.context["title_placeholders"] = {"host": parsed_url.hostname}
self.deconz_config = {
@ -217,18 +203,18 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
This flow is triggered by the discovery component.
"""
bridgeid = user_input[CONF_SERIAL]
gateway_entries = configured_gateways(self.hass)
self.bridge_id = normalize_bridge_id(user_input[CONF_SERIAL])
gateway = self.hass.data.get(DOMAIN, {}).get(self.bridge_id)
if bridgeid in gateway_entries:
entry = gateway_entries[bridgeid]
if gateway:
return self._update_entry(
entry,
gateway.config_entry,
user_input[CONF_HOST],
user_input[CONF_PORT],
user_input[CONF_API_KEY],
)
await self.async_set_unique_id(self.bridge_id)
self._hassio_discovery = user_input
return await self.async_step_hassio_confirm()
@ -239,7 +225,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self.deconz_config = {
CONF_HOST: self._hassio_discovery[CONF_HOST],
CONF_PORT: self._hassio_discovery[CONF_PORT],
CONF_BRIDGEID: self._hassio_discovery[CONF_SERIAL],
CONF_API_KEY: self._hassio_discovery[CONF_API_KEY],
}

View File

@ -6,7 +6,6 @@ _LOGGER = logging.getLogger(__package__)
DOMAIN = "deconz"
CONF_BRIDGEID = "bridgeid"
CONF_UUID = "uuid"
DEFAULT_PORT = 80
DEFAULT_ALLOW_CLIP_SENSOR = False

View File

@ -15,9 +15,7 @@ from homeassistant.const import (
)
from . import DOMAIN
from .config_flow import configured_gateways
from .deconz_event import CONF_DECONZ_EVENT, CONF_UNIQUE_ID
from .gateway import get_gateway_from_config_entry
CONF_SUBTYPE = "subtype"
@ -287,10 +285,8 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend(
def _get_deconz_event_from_device_id(hass, device_id):
"""Resolve deconz event from device id."""
deconz_config_entries = configured_gateways(hass)
for config_entry in deconz_config_entries.values():
for gateway in hass.data.get(DOMAIN):
gateway = get_gateway_from_config_entry(hass, config_entry)
for deconz_event in gateway.events:
if device_id == deconz_event.device_id:

View File

@ -22,7 +22,6 @@ from .const import (
_LOGGER,
CONF_ALLOW_CLIP_SENSOR,
CONF_ALLOW_DECONZ_GROUPS,
CONF_BRIDGEID,
CONF_MASTER_GATEWAY,
DEFAULT_ALLOW_CLIP_SENSOR,
DEFAULT_ALLOW_DECONZ_GROUPS,
@ -36,7 +35,7 @@ from .errors import AuthenticationRequired, CannotConnect
@callback
def get_gateway_from_config_entry(hass, config_entry):
"""Return gateway with a matching bridge id."""
return hass.data[DOMAIN][config_entry.data[CONF_BRIDGEID]]
return hass.data[DOMAIN][config_entry.unique_id]
class DeconzGateway:
@ -56,7 +55,7 @@ class DeconzGateway:
@property
def bridgeid(self) -> str:
"""Return the unique identifier of the gateway."""
return self.config_entry.data[CONF_BRIDGEID]
return self.config_entry.unique_id
@property
def master(self) -> bool:
@ -92,11 +91,9 @@ class DeconzGateway:
async def async_setup(self) -> bool:
"""Set up a deCONZ gateway."""
hass = self.hass
try:
self.api = await get_gateway(
hass,
self.hass,
self.config_entry.data,
self.async_add_device_callback,
self.async_connection_status_callback,
@ -110,8 +107,8 @@ class DeconzGateway:
return False
for component in SUPPORTED_PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(
self.hass.async_create_task(
self.hass.config_entries.async_forward_entry_setup(
self.config_entry, component
)
)

View File

@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/deconz",
"requirements": [
"pydeconz==65"
"pydeconz==66"
],
"ssdp": [
{

View File

@ -1187,7 +1187,7 @@ pydaikin==1.6.1
pydanfossair==0.1.0
# homeassistant.components.deconz
pydeconz==65
pydeconz==66
# homeassistant.components.delijn
pydelijn==0.5.1

View File

@ -410,7 +410,7 @@ pycoolmasternet==0.0.4
pydaikin==1.6.1
# homeassistant.components.deconz
pydeconz==65
pydeconz==66
# homeassistant.components.zwave
pydispatcher==2.0.5

View File

@ -1,11 +1,20 @@
"""Tests for deCONZ config flow."""
import asyncio
from unittest.mock import Mock, patch
from copy import deepcopy
from asynctest import Mock, patch
import pydeconz
from homeassistant.components import ssdp
from homeassistant.components.deconz import config_flow
from homeassistant.components.deconz.const import CONF_BRIDGEID
from .test_gateway import (
BRIDGEID,
DECONZ_WEB_REQUEST,
ENTRY_CONFIG,
setup_deconz_integration,
)
from tests.common import MockConfigEntry
@ -14,7 +23,7 @@ async def test_flow_works(hass, aioclient_mock):
"""Test that config flow works."""
aioclient_mock.get(
pydeconz.utils.URL_DISCOVER,
json=[{"id": "id", "internalipaddress": "1.2.3.4", "internalport": 80}],
json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}],
headers={"content-type": "application/json"},
)
aioclient_mock.post(
@ -35,9 +44,8 @@ async def test_flow_works(hass, aioclient_mock):
)
assert result["type"] == "create_entry"
assert result["title"] == "deCONZ-id"
assert result["title"] == BRIDGEID
assert result["data"] == {
config_flow.CONF_BRIDGEID: "id",
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 80,
config_flow.CONF_API_KEY: "1234567890ABCDEF",
@ -117,12 +125,12 @@ async def test_user_step_two_bridges_selection(hass, aioclient_mock):
flow.hass = hass
flow.bridges = [
{
config_flow.CONF_BRIDGEID: "id1",
CONF_BRIDGEID: "id1",
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 80,
},
{
config_flow.CONF_BRIDGEID: "id2",
CONF_BRIDGEID: "id2",
config_flow.CONF_HOST: "5.6.7.8",
config_flow.CONF_PORT: 80,
},
@ -241,25 +249,22 @@ 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: "123ABC",
config_flow.CONF_UUID: "456DEF",
},
source="user",
data={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80},
unique_id=BRIDGEID,
)
entry.add_to_hass(hass)
gateway = Mock()
gateway.config_entry = entry
hass.data[config_flow.DOMAIN] = {"123ABC": gateway}
hass.data[config_flow.DOMAIN] = {BRIDGEID: gateway}
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "123ABC",
ssdp.ATTR_UPNP_UDN: "uuid:456DEF",
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
},
context={"source": "ssdp"},
)
@ -277,8 +282,8 @@ async def test_bridge_discovery_dont_update_existing_hassio_entry(hass):
data={
config_flow.CONF_HOST: "core-deconz",
config_flow.CONF_BRIDGEID: "123ABC",
config_flow.CONF_UUID: "456DEF",
},
unique_id="123ABC",
)
entry.add_to_hass(hass)
@ -292,7 +297,6 @@ async def test_bridge_discovery_dont_update_existing_hassio_entry(hass):
ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/",
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
ssdp.ATTR_UPNP_SERIAL: "123ABC",
ssdp.ATTR_UPNP_UDN: "uuid:456DEF",
},
context={"source": "ssdp"},
)
@ -306,11 +310,12 @@ 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": "123ABC", "uuid": "456DEF"},
json={"bridgeid": BRIDGEID, "uuid": "456DEF"},
headers={"content-type": "application/json"},
)
flow = config_flow.DeconzFlowHandler()
flow.context = {}
flow.hass = hass
flow.deconz_config = {
config_flow.CONF_HOST: "1.2.3.4",
@ -321,13 +326,11 @@ async def test_create_entry(hass, aioclient_mock):
result = await flow._create_entry()
assert result["type"] == "create_entry"
assert result["title"] == "deCONZ-123ABC"
assert result["title"] == BRIDGEID
assert result["data"] == {
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",
}
@ -342,7 +345,7 @@ async def test_create_entry_timeout(hass, aioclient_mock):
}
with patch(
"homeassistant.components.deconz.config_flow.async_get_gateway_config",
"homeassistant.components.deconz.config_flow.async_get_bridge_id",
side_effect=asyncio.TimeoutError,
):
result = await flow._create_entry()
@ -353,54 +356,44 @@ async def test_create_entry_timeout(hass, aioclient_mock):
async def test_hassio_update_instance(hass):
"""Test we can update an existing config entry."""
entry = MockConfigEntry(
domain=config_flow.DOMAIN,
data={
config_flow.CONF_BRIDGEID: "id",
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 40850,
config_flow.CONF_API_KEY: "secret",
},
data = deepcopy(DECONZ_WEB_REQUEST)
entry_config = deepcopy(ENTRY_CONFIG)
gateway = await setup_deconz_integration(
hass, entry_config, options={}, get_state_response=data
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "mock-deconz",
config_flow.CONF_HOST: "2.3.4.5",
config_flow.CONF_PORT: 8080,
config_flow.CONF_API_KEY: "updated",
config_flow.CONF_SERIAL: "id",
config_flow.CONF_SERIAL: BRIDGEID,
},
context={"source": "hassio"},
)
assert result["type"] == "abort"
assert result["reason"] == "updated_instance"
assert entry.data[config_flow.CONF_HOST] == "mock-deconz"
assert entry.data[config_flow.CONF_PORT] == 8080
assert entry.data[config_flow.CONF_API_KEY] == "updated"
assert gateway.config_entry.data[config_flow.CONF_HOST] == "2.3.4.5"
assert gateway.config_entry.data[config_flow.CONF_PORT] == 8080
assert gateway.config_entry.data[config_flow.CONF_API_KEY] == "updated"
async def test_hassio_dont_update_instance(hass):
"""Test we can update an existing config entry."""
entry = MockConfigEntry(
domain=config_flow.DOMAIN,
data={
config_flow.CONF_BRIDGEID: "id",
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 8080,
config_flow.CONF_API_KEY: "secret",
},
data = deepcopy(DECONZ_WEB_REQUEST)
await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
data={
config_flow.CONF_HOST: "1.2.3.4",
config_flow.CONF_PORT: 8080,
config_flow.CONF_API_KEY: "secret",
config_flow.CONF_SERIAL: "id",
config_flow.CONF_PORT: 80,
config_flow.CONF_API_KEY: "ABCDEF",
config_flow.CONF_SERIAL: BRIDGEID,
},
context={"source": "hassio"},
)
@ -417,7 +410,7 @@ async def test_hassio_confirm(hass):
"addon": "Mock Addon",
config_flow.CONF_HOST: "mock-deconz",
config_flow.CONF_PORT: 80,
config_flow.CONF_SERIAL: "id",
config_flow.CONF_SERIAL: BRIDGEID,
config_flow.CONF_API_KEY: "1234567890ABCDEF",
},
context={"source": "hassio"},
@ -434,7 +427,6 @@ async def test_hassio_confirm(hass):
assert result["result"].data == {
config_flow.CONF_HOST: "mock-deconz",
config_flow.CONF_PORT: 80,
config_flow.CONF_BRIDGEID: "id",
config_flow.CONF_API_KEY: "1234567890ABCDEF",
}

View File

@ -10,14 +10,12 @@ from homeassistant.components import deconz, ssdp
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.dispatcher import async_dispatcher_connect
BRIDGEID = "0123456789"
BRIDGEID = "01234E56789A"
ENTRY_CONFIG = {
deconz.config_flow.CONF_API_KEY: "ABCDEF",
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 = {
@ -60,7 +58,8 @@ async def setup_deconz_integration(hass, config, options, get_state_response):
hass.config_entries._entries.append(config_entry)
return hass.data[deconz.DOMAIN].get(config[deconz.CONF_BRIDGEID])
bridgeid = get_state_response["config"]["bridgeid"]
return hass.data[deconz.DOMAIN].get(bridgeid)
async def test_gateway_setup(hass):

View File

@ -1,13 +1,14 @@
"""Test deCONZ component setup process."""
import asyncio
from copy import deepcopy
from asynctest import Mock, patch
from asynctest import patch
import pytest
from homeassistant.components import deconz
from homeassistant.exceptions import ConfigEntryNotReady
from tests.common import MockConfigEntry
from .test_gateway import DECONZ_WEB_REQUEST, ENTRY_CONFIG, setup_deconz_integration
ENTRY1_HOST = "1.2.3.4"
ENTRY1_PORT = 80
@ -34,138 +35,83 @@ async def setup_entry(hass, entry):
async def test_setup_entry_fails(hass):
"""Test setup entry fails if deCONZ is not available."""
entry = Mock()
entry.data = {
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
deconz.config_flow.CONF_PORT: ENTRY1_PORT,
deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY,
}
data = deepcopy(DECONZ_WEB_REQUEST)
with patch("pydeconz.DeconzSession.initialize", side_effect=Exception):
await deconz.async_setup_entry(hass, entry)
await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
assert not hass.data[deconz.DOMAIN]
async def test_setup_entry_no_available_bridge(hass):
"""Test setup entry fails if deCONZ is not available."""
entry = Mock()
entry.data = {
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
deconz.config_flow.CONF_PORT: ENTRY1_PORT,
deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY,
}
data = deepcopy(DECONZ_WEB_REQUEST)
with patch(
"pydeconz.DeconzSession.initialize", side_effect=asyncio.TimeoutError
), pytest.raises(ConfigEntryNotReady):
await deconz.async_setup_entry(hass, entry)
await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
async def test_setup_entry_successful(hass):
"""Test setup entry is successful."""
entry = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
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,
},
data = deepcopy(DECONZ_WEB_REQUEST)
gateway = await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
entry.add_to_hass(hass)
await setup_entry(hass, entry)
assert ENTRY1_BRIDGEID in hass.data[deconz.DOMAIN]
assert hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].master
assert hass.data[deconz.DOMAIN]
assert gateway.bridgeid in hass.data[deconz.DOMAIN]
assert hass.data[deconz.DOMAIN][gateway.bridgeid].master
async def test_setup_entry_multiple_gateways(hass):
"""Test setup entry is successful with multiple gateways."""
entry = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
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,
},
data = deepcopy(DECONZ_WEB_REQUEST)
gateway = await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
entry.add_to_hass(hass)
entry2 = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY2_HOST,
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,
},
data2 = deepcopy(DECONZ_WEB_REQUEST)
data2["config"]["bridgeid"] = "01234E56789B"
gateway2 = await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data2
)
entry2.add_to_hass(hass)
await setup_entry(hass, entry)
await setup_entry(hass, entry2)
assert ENTRY1_BRIDGEID in hass.data[deconz.DOMAIN]
assert hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].master
assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN]
assert not hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master
assert len(hass.data[deconz.DOMAIN]) == 2
assert hass.data[deconz.DOMAIN][gateway.bridgeid].master
assert not hass.data[deconz.DOMAIN][gateway2.bridgeid].master
async def test_unload_entry(hass):
"""Test being able to unload an entry."""
entry = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
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,
},
data = deepcopy(DECONZ_WEB_REQUEST)
gateway = await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
entry.add_to_hass(hass)
await setup_entry(hass, entry)
with patch.object(deconz.DeconzGateway, "async_reset", return_value=True):
assert await deconz.async_unload_entry(hass, entry)
assert hass.data[deconz.DOMAIN]
assert await deconz.async_unload_entry(hass, gateway.config_entry)
assert not hass.data[deconz.DOMAIN]
async def test_unload_entry_multiple_gateways(hass):
"""Test being able to unload an entry and master gateway gets moved."""
entry = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
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,
},
data = deepcopy(DECONZ_WEB_REQUEST)
gateway = await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
entry.add_to_hass(hass)
entry2 = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY2_HOST,
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,
},
data2 = deepcopy(DECONZ_WEB_REQUEST)
data2["config"]["bridgeid"] = "01234E56789B"
gateway2 = await setup_deconz_integration(
hass, ENTRY_CONFIG, options={}, get_state_response=data2
)
entry2.add_to_hass(hass)
await setup_entry(hass, entry)
await setup_entry(hass, entry2)
assert len(hass.data[deconz.DOMAIN]) == 2
with patch.object(deconz.DeconzGateway, "async_reset", return_value=True):
assert await deconz.async_unload_entry(hass, entry)
assert await deconz.async_unload_entry(hass, gateway.config_entry)
assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN]
assert hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master
assert len(hass.data[deconz.DOMAIN]) == 1
assert hass.data[deconz.DOMAIN][gateway2.bridgeid].master

View File

@ -6,6 +6,7 @@ import pytest
import voluptuous as vol
from homeassistant.components import deconz
from homeassistant.components.deconz.const import CONF_BRIDGEID
from .test_gateway import (
BRIDGEID,
@ -99,7 +100,7 @@ async def test_configure_service_with_field(hass):
data = {
deconz.services.SERVICE_FIELD: "/light/2",
deconz.CONF_BRIDGEID: BRIDGEID,
CONF_BRIDGEID: BRIDGEID,
deconz.services.SERVICE_DATA: {"on": True, "attr1": 10, "attr2": 20},
}
@ -203,7 +204,7 @@ async def test_service_refresh_devices(hass):
hass, ENTRY_CONFIG, options={}, get_state_response=data
)
data = {deconz.CONF_BRIDGEID: BRIDGEID}
data = {CONF_BRIDGEID: BRIDGEID}
with patch(
"pydeconz.DeconzSession.request",