Improve deCONZ services code quality (#56904)

* setup and unload services does not need to be async

* Only use DECONZ_DOMAIN to decide if service should be setup

* Consolidation of functionality

* Make a service to schema dictionary
This commit is contained in:
Robert Svensson 2021-10-01 20:31:38 +02:00 committed by GitHub
parent 15a8f6741b
commit 8d06527cb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 77 deletions

View File

@ -32,12 +32,13 @@ async def async_setup_entry(hass, config_entry):
if not await gateway.async_setup(): if not await gateway.async_setup():
return False return False
if not hass.data[DOMAIN]:
async_setup_services(hass)
hass.data[DOMAIN][config_entry.entry_id] = gateway hass.data[DOMAIN][config_entry.entry_id] = gateway
await gateway.async_update_device_registry() await gateway.async_update_device_registry()
await async_setup_services(hass)
config_entry.async_on_unload( config_entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown)
) )
@ -50,7 +51,7 @@ async def async_unload_entry(hass, config_entry):
gateway = hass.data[DOMAIN].pop(config_entry.entry_id) gateway = hass.data[DOMAIN].pop(config_entry.entry_id)
if not hass.data[DOMAIN]: if not hass.data[DOMAIN]:
await async_unload_services(hass) async_unload_services(hass)
elif gateway.master: elif gateway.master:
await async_update_master_gateway(hass, config_entry) await async_update_master_gateway(hass, config_entry)

View File

@ -5,6 +5,7 @@ import asyncio
from pydeconz.utils import normalize_bridge_id from pydeconz.utils import normalize_bridge_id
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity_registry import ( from homeassistant.helpers.entity_registry import (
@ -46,13 +47,22 @@ SERVICE_DEVICE_REFRESH = "device_refresh"
SERVICE_REMOVE_ORPHANED_ENTRIES = "remove_orphaned_entries" SERVICE_REMOVE_ORPHANED_ENTRIES = "remove_orphaned_entries"
SELECT_GATEWAY_SCHEMA = vol.All(vol.Schema({vol.Optional(CONF_BRIDGE_ID): str})) SELECT_GATEWAY_SCHEMA = vol.All(vol.Schema({vol.Optional(CONF_BRIDGE_ID): str}))
SUPPORTED_SERVICES = (
SERVICE_CONFIGURE_DEVICE,
SERVICE_DEVICE_REFRESH,
SERVICE_REMOVE_ORPHANED_ENTRIES,
)
async def async_setup_services(hass): SERVICE_TO_SCHEMA = {
SERVICE_CONFIGURE_DEVICE: SERVICE_CONFIGURE_DEVICE_SCHEMA,
SERVICE_DEVICE_REFRESH: SELECT_GATEWAY_SCHEMA,
SERVICE_REMOVE_ORPHANED_ENTRIES: SELECT_GATEWAY_SCHEMA,
}
@callback
def async_setup_services(hass):
"""Set up services for deCONZ integration.""" """Set up services for deCONZ integration."""
if hass.data.get(DECONZ_SERVICES, False):
return
hass.data[DECONZ_SERVICES] = True
async def async_call_deconz_service(service_call): async def async_call_deconz_service(service_call):
"""Call correct deCONZ service.""" """Call correct deCONZ service."""
@ -83,38 +93,20 @@ async def async_setup_services(hass):
elif service == SERVICE_REMOVE_ORPHANED_ENTRIES: elif service == SERVICE_REMOVE_ORPHANED_ENTRIES:
await async_remove_orphaned_entries_service(gateway) await async_remove_orphaned_entries_service(gateway)
for service in SUPPORTED_SERVICES:
hass.services.async_register( hass.services.async_register(
DOMAIN, DOMAIN,
SERVICE_CONFIGURE_DEVICE, service,
async_call_deconz_service, async_call_deconz_service,
schema=SERVICE_CONFIGURE_DEVICE_SCHEMA, schema=SERVICE_TO_SCHEMA[service],
)
hass.services.async_register(
DOMAIN,
SERVICE_DEVICE_REFRESH,
async_call_deconz_service,
schema=SELECT_GATEWAY_SCHEMA,
)
hass.services.async_register(
DOMAIN,
SERVICE_REMOVE_ORPHANED_ENTRIES,
async_call_deconz_service,
schema=SELECT_GATEWAY_SCHEMA,
) )
async def async_unload_services(hass): @callback
def async_unload_services(hass):
"""Unload deCONZ services.""" """Unload deCONZ services."""
if not hass.data.get(DECONZ_SERVICES): for service in SUPPORTED_SERVICES:
return hass.services.async_remove(DOMAIN, service)
hass.data[DECONZ_SERVICES] = False
hass.services.async_remove(DOMAIN, SERVICE_CONFIGURE_DEVICE)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)
hass.services.async_remove(DOMAIN, SERVICE_REMOVE_ORPHANED_ENTRIES)
async def async_configure_service(gateway, data): async def async_configure_service(gateway, data):

View File

@ -1,5 +1,5 @@
"""deCONZ service tests.""" """deCONZ service tests."""
from unittest.mock import Mock, patch from unittest.mock import patch
import pytest import pytest
import voluptuous as vol import voluptuous as vol
@ -10,15 +10,13 @@ from homeassistant.components.deconz.const import (
) )
from homeassistant.components.deconz.deconz_event import CONF_DECONZ_EVENT from homeassistant.components.deconz.deconz_event import CONF_DECONZ_EVENT
from homeassistant.components.deconz.services import ( from homeassistant.components.deconz.services import (
DECONZ_SERVICES,
SERVICE_CONFIGURE_DEVICE, SERVICE_CONFIGURE_DEVICE,
SERVICE_DATA, SERVICE_DATA,
SERVICE_DEVICE_REFRESH, SERVICE_DEVICE_REFRESH,
SERVICE_ENTITY, SERVICE_ENTITY,
SERVICE_FIELD, SERVICE_FIELD,
SERVICE_REMOVE_ORPHANED_ENTRIES, SERVICE_REMOVE_ORPHANED_ENTRIES,
async_setup_services, SUPPORTED_SERVICES,
async_unload_services,
) )
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers import device_registry as dr, entity_registry as er
@ -35,46 +33,33 @@ from .test_gateway import (
from tests.common import async_capture_events from tests.common import async_capture_events
async def test_service_setup(hass): async def test_service_setup_and_unload(hass, aioclient_mock):
"""Verify service setup works.""" """Verify service setup works."""
assert DECONZ_SERVICES not in hass.data config_entry = await setup_deconz_integration(hass, aioclient_mock)
with patch( for service in SUPPORTED_SERVICES:
"homeassistant.core.ServiceRegistry.async_register", return_value=Mock(True) assert hass.services.has_service(DECONZ_DOMAIN, service)
) as async_register:
await async_setup_services(hass) assert await hass.config_entries.async_unload(config_entry.entry_id)
assert hass.data[DECONZ_SERVICES] is True for service in SUPPORTED_SERVICES:
assert async_register.call_count == 3 assert not hass.services.has_service(DECONZ_DOMAIN, service)
async def test_service_setup_already_registered(hass): @patch("homeassistant.core.ServiceRegistry.async_remove")
"""Make sure that services are only registered once.""" @patch("homeassistant.core.ServiceRegistry.async_register")
hass.data[DECONZ_SERVICES] = True async def test_service_setup_and_unload_not_called_if_multiple_integrations_detected(
with patch( register_service_mock, remove_service_mock, hass, aioclient_mock
"homeassistant.core.ServiceRegistry.async_register", return_value=Mock(True) ):
) as async_register: """Make sure that services are only setup and removed once."""
await async_setup_services(hass) config_entry = await setup_deconz_integration(hass, aioclient_mock)
async_register.assert_not_called() register_service_mock.reset_mock()
config_entry_2 = await setup_deconz_integration(hass, aioclient_mock, entry_id=2)
register_service_mock.assert_not_called()
register_service_mock.assert_not_called()
async def test_service_unload(hass): assert await hass.config_entries.async_unload(config_entry_2.entry_id)
"""Verify service unload works.""" remove_service_mock.assert_not_called()
hass.data[DECONZ_SERVICES] = True assert await hass.config_entries.async_unload(config_entry.entry_id)
with patch( assert remove_service_mock.call_count == 3
"homeassistant.core.ServiceRegistry.async_remove", return_value=Mock(True)
) as async_remove:
await async_unload_services(hass)
assert hass.data[DECONZ_SERVICES] is False
assert async_remove.call_count == 3
async def test_service_unload_not_registered(hass):
"""Make sure that services can only be unloaded once."""
with patch(
"homeassistant.core.ServiceRegistry.async_remove", return_value=Mock(True)
) as async_remove:
await async_unload_services(hass)
assert DECONZ_SERVICES not in hass.data
async_remove.assert_not_called()
async def test_configure_service_with_field(hass, aioclient_mock): async def test_configure_service_with_field(hass, aioclient_mock):