mirror of https://github.com/home-assistant/core
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:
parent
c130e81638
commit
0a4f3ec1ec
|
@ -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)
|
||||
|
|
|
@ -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],
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ _LOGGER = logging.getLogger(__package__)
|
|||
DOMAIN = "deconz"
|
||||
|
||||
CONF_BRIDGEID = "bridgeid"
|
||||
CONF_UUID = "uuid"
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
DEFAULT_ALLOW_CLIP_SENSOR = False
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/deconz",
|
||||
"requirements": [
|
||||
"pydeconz==65"
|
||||
"pydeconz==66"
|
||||
],
|
||||
"ssdp": [
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue