Make use of entry id rather than unique id when storing deconz entry in hass.data (#52584)

* Make use of entry id rather than unique id when storing entry in hass data

* Update homeassistant/components/deconz/services.py

Co-authored-by: Franck Nijhof <frenck@frenck.nl>

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
pull/52513/head
Robert Svensson 2021-07-06 17:18:54 +02:00 committed by GitHub
parent 7ba1fdea70
commit 605f65b75d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 37 deletions

View File

@ -20,8 +20,7 @@ async def async_setup_entry(hass, config_entry):
Load config, group, light and sensor data for server information.
Start websocket for push notification of state changes from deCONZ.
"""
if DOMAIN not in hass.data:
hass.data[DOMAIN] = {}
hass.data.setdefault(DOMAIN, {})
await async_update_group_unique_id(hass, config_entry)
@ -33,7 +32,7 @@ async def async_setup_entry(hass, config_entry):
if not await gateway.async_setup():
return False
hass.data[DOMAIN][config_entry.unique_id] = gateway
hass.data[DOMAIN][config_entry.entry_id] = gateway
await gateway.async_update_device_registry()
@ -48,7 +47,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.unique_id)
gateway = hass.data[DOMAIN].pop(config_entry.entry_id)
if not hass.data[DOMAIN]:
await async_unload_services(hass)

View File

@ -33,8 +33,8 @@ 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[DECONZ_DOMAIN][config_entry.unique_id]
"""Return gateway with a matching config entry ID."""
return hass.data[DECONZ_DOMAIN][config_entry.entry_id]
class DeconzGateway:

View File

@ -59,14 +59,29 @@ async def async_setup_services(hass):
service = service_call.service
service_data = service_call.data
gateway = get_master_gateway(hass)
if CONF_BRIDGE_ID in service_data:
found_gateway = False
bridge_id = normalize_bridge_id(service_data[CONF_BRIDGE_ID])
for possible_gateway in hass.data[DOMAIN].values():
if possible_gateway.bridgeid == bridge_id:
gateway = possible_gateway
found_gateway = True
break
if not found_gateway:
LOGGER.error("Could not find the gateway %s", bridge_id)
return
if service == SERVICE_CONFIGURE_DEVICE:
await async_configure_service(hass, service_data)
await async_configure_service(gateway, service_data)
elif service == SERVICE_DEVICE_REFRESH:
await async_refresh_devices_service(hass, service_data)
await async_refresh_devices_service(gateway)
elif service == SERVICE_REMOVE_ORPHANED_ENTRIES:
await async_remove_orphaned_entries_service(hass, service_data)
await async_remove_orphaned_entries_service(gateway)
hass.services.async_register(
DOMAIN,
@ -102,7 +117,7 @@ async def async_unload_services(hass):
hass.services.async_remove(DOMAIN, SERVICE_REMOVE_ORPHANED_ENTRIES)
async def async_configure_service(hass, data):
async def async_configure_service(gateway, data):
"""Set attribute of device in deCONZ.
Entity is used to resolve to a device path (e.g. '/lights/1').
@ -118,10 +133,6 @@ async def async_configure_service(hass, data):
See Dresden Elektroniks REST API documentation for details:
http://dresden-elektronik.github.io/deconz-rest-doc/rest/
"""
gateway = get_master_gateway(hass)
if CONF_BRIDGE_ID in data:
gateway = hass.data[DOMAIN][normalize_bridge_id(data[CONF_BRIDGE_ID])]
field = data.get(SERVICE_FIELD, "")
entity_id = data.get(SERVICE_ENTITY)
data = data[SERVICE_DATA]
@ -136,31 +147,21 @@ async def async_configure_service(hass, data):
await gateway.api.request("put", field, json=data)
async def async_refresh_devices_service(hass, data):
async def async_refresh_devices_service(gateway):
"""Refresh available devices from deCONZ."""
gateway = get_master_gateway(hass)
if CONF_BRIDGE_ID in data:
gateway = hass.data[DOMAIN][normalize_bridge_id(data[CONF_BRIDGE_ID])]
gateway.ignore_state_updates = True
await gateway.api.refresh_state()
gateway.ignore_state_updates = False
gateway.async_add_device_callback(NEW_GROUP, force=True)
gateway.async_add_device_callback(NEW_LIGHT, force=True)
gateway.async_add_device_callback(NEW_SCENE, force=True)
gateway.async_add_device_callback(NEW_SENSOR, force=True)
for new_device_type in [NEW_GROUP, NEW_LIGHT, NEW_SCENE, NEW_SENSOR]:
gateway.async_add_device_callback(new_device_type, force=True)
async def async_remove_orphaned_entries_service(hass, data):
async def async_remove_orphaned_entries_service(gateway):
"""Remove orphaned deCONZ entries from device and entity registries."""
gateway = get_master_gateway(hass)
if CONF_BRIDGE_ID in data:
gateway = hass.data[DOMAIN][normalize_bridge_id(data[CONF_BRIDGE_ID])]
device_registry, entity_registry = await asyncio.gather(
hass.helpers.device_registry.async_get_registry(),
hass.helpers.entity_registry.async_get_registry(),
gateway.hass.helpers.device_registry.async_get_registry(),
gateway.hass.helpers.entity_registry.async_get_registry(),
)
entity_entries = async_entries_for_config_entry(

View File

@ -61,8 +61,8 @@ async def test_setup_entry_successful(hass, aioclient_mock):
config_entry = await setup_deconz_integration(hass, aioclient_mock)
assert hass.data[DECONZ_DOMAIN]
assert config_entry.unique_id in hass.data[DECONZ_DOMAIN]
assert hass.data[DECONZ_DOMAIN][config_entry.unique_id].master
assert config_entry.entry_id in hass.data[DECONZ_DOMAIN]
assert hass.data[DECONZ_DOMAIN][config_entry.entry_id].master
async def test_setup_entry_multiple_gateways(hass, aioclient_mock):
@ -80,8 +80,8 @@ async def test_setup_entry_multiple_gateways(hass, aioclient_mock):
)
assert len(hass.data[DECONZ_DOMAIN]) == 2
assert hass.data[DECONZ_DOMAIN][config_entry.unique_id].master
assert not hass.data[DECONZ_DOMAIN][config_entry2.unique_id].master
assert hass.data[DECONZ_DOMAIN][config_entry.entry_id].master
assert not hass.data[DECONZ_DOMAIN][config_entry2.entry_id].master
async def test_unload_entry(hass, aioclient_mock):
@ -112,7 +112,7 @@ async def test_unload_entry_multiple_gateways(hass, aioclient_mock):
assert await async_unload_entry(hass, config_entry)
assert len(hass.data[DECONZ_DOMAIN]) == 1
assert hass.data[DECONZ_DOMAIN][config_entry2.unique_id].master
assert hass.data[DECONZ_DOMAIN][config_entry2.entry_id].master
async def test_update_group_unique_id(hass):

View File

@ -152,8 +152,27 @@ async def test_configure_service_with_entity_and_field(hass, aioclient_mock):
assert aioclient_mock.mock_calls[1][2] == {"on": True, "attr1": 10, "attr2": 20}
async def test_configure_service_with_faulty_bridgeid(hass, aioclient_mock):
"""Test that service fails on a bad bridge id."""
await setup_deconz_integration(hass, aioclient_mock)
aioclient_mock.clear_requests()
data = {
CONF_BRIDGE_ID: "Bad bridge id",
SERVICE_FIELD: "/lights/1",
SERVICE_DATA: {"on": True},
}
await hass.services.async_call(
DECONZ_DOMAIN, SERVICE_CONFIGURE_DEVICE, service_data=data
)
await hass.async_block_till_done()
assert len(aioclient_mock.mock_calls) == 0
async def test_configure_service_with_faulty_field(hass, aioclient_mock):
"""Test that service invokes pydeconz with the correct path and data."""
"""Test that service fails on a bad field."""
await setup_deconz_integration(hass, aioclient_mock)
data = {SERVICE_FIELD: "light/2", SERVICE_DATA: {}}
@ -166,7 +185,7 @@ async def test_configure_service_with_faulty_field(hass, aioclient_mock):
async def test_configure_service_with_faulty_entity(hass, aioclient_mock):
"""Test that service invokes pydeconz with the correct path and data."""
"""Test that service on a non existing entity."""
await setup_deconz_integration(hass, aioclient_mock)
aioclient_mock.clear_requests()