diff --git a/homeassistant/components/fritz/__init__.py b/homeassistant/components/fritz/__init__.py index 1e1830ca1c1..b7194d9cabd 100644 --- a/homeassistant/components/fritz/__init__.py +++ b/homeassistant/components/fritz/__init__.py @@ -2,6 +2,8 @@ import logging +import voluptuous as vol + from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_HOST, @@ -10,8 +12,15 @@ from homeassistant.const import ( CONF_SSL, CONF_USERNAME, ) -from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady +from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.exceptions import ( + ConfigEntryAuthFailed, + ConfigEntryNotReady, + HomeAssistantError, +) +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.service import async_extract_config_entry_ids +from homeassistant.helpers.typing import ConfigType from .const import ( DATA_FRITZ, @@ -20,12 +29,60 @@ from .const import ( FRITZ_AUTH_EXCEPTIONS, FRITZ_EXCEPTIONS, PLATFORMS, + SERVICE_SET_GUEST_WIFI_PW, ) from .coordinator import AvmWrapper, FritzData -from .services import async_setup_services, async_unload_services _LOGGER = logging.getLogger(__name__) +CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN) + +SERVICE_SCHEMA_SET_GUEST_WIFI_PW = vol.Schema( + { + vol.Required("device_id"): str, + vol.Optional("password"): vol.Length(min=8, max=63), + vol.Optional("length"): vol.Range(min=8, max=63), + } +) + +SERVICE_LIST: list[tuple[str, vol.Schema | None]] = [ + (SERVICE_SET_GUEST_WIFI_PW, SERVICE_SCHEMA_SET_GUEST_WIFI_PW), +] + + +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: + """Set up fritzboxtools services.""" + for service, _ in SERVICE_LIST: + if hass.services.has_service(DOMAIN, service): + return True + + async def async_call_fritz_service(service_call: ServiceCall) -> None: + """Call correct Fritz service.""" + + target_entry_ids = await async_extract_config_entry_ids(hass, service_call) + target_entries = [ + loaded_entry + for loaded_entry in hass.config_entries.async_loaded_entries(DOMAIN) + if loaded_entry.entry_id in target_entry_ids + ] + + if not target_entries: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="config_entry_not_found", + translation_placeholders={"service": service_call.service}, + ) + + for target_entry in target_entries: + _LOGGER.debug("Executing service %s", service_call.service) + avm_wrapper: AvmWrapper = hass.data[DOMAIN][target_entry.entry_id] + await avm_wrapper.service_fritzbox(service_call, target_entry) + + for service, schema in SERVICE_LIST: + hass.services.async_register(DOMAIN, service, async_call_fritz_service, schema) + + return True + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up fritzboxtools from config entry.""" @@ -65,8 +122,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Load the other platforms like switch await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - await async_setup_services(hass) - return True @@ -84,8 +139,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if unload_ok: hass.data[DOMAIN].pop(entry.entry_id) - await async_unload_services(hass) - return unload_ok diff --git a/homeassistant/components/fritz/quality_scale.yaml b/homeassistant/components/fritz/quality_scale.yaml index 06c572f93a6..d6fadd3a20e 100644 --- a/homeassistant/components/fritz/quality_scale.yaml +++ b/homeassistant/components/fritz/quality_scale.yaml @@ -1,8 +1,6 @@ rules: # Bronze - action-setup: - status: todo - comment: still in async_setup_entry, needs to be moved to async_setup + action-setup: done appropriate-polling: done brands: done common-modules: done diff --git a/homeassistant/components/fritz/services.py b/homeassistant/components/fritz/services.py deleted file mode 100644 index bace7480ba5..00000000000 --- a/homeassistant/components/fritz/services.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Services for Fritz integration.""" - -from __future__ import annotations - -import logging - -import voluptuous as vol - -from homeassistant.config_entries import ConfigEntryState -from homeassistant.core import HomeAssistant, ServiceCall -from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers.service import async_extract_config_entry_ids - -from .const import DOMAIN, FRITZ_SERVICES, SERVICE_SET_GUEST_WIFI_PW -from .coordinator import AvmWrapper - -_LOGGER = logging.getLogger(__name__) - -SERVICE_SCHEMA_SET_GUEST_WIFI_PW = vol.Schema( - { - vol.Required("device_id"): str, - vol.Optional("password"): vol.Length(min=8, max=63), - vol.Optional("length"): vol.Range(min=8, max=63), - } -) - -SERVICE_LIST: list[tuple[str, vol.Schema | None]] = [ - (SERVICE_SET_GUEST_WIFI_PW, SERVICE_SCHEMA_SET_GUEST_WIFI_PW), -] - - -async def async_setup_services(hass: HomeAssistant) -> None: - """Set up services for Fritz integration.""" - - for service, _ in SERVICE_LIST: - if hass.services.has_service(DOMAIN, service): - return - - async def async_call_fritz_service(service_call: ServiceCall) -> None: - """Call correct Fritz service.""" - - if not ( - fritzbox_entry_ids := await _async_get_configured_avm_device( - hass, service_call - ) - ): - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="config_entry_not_found", - translation_placeholders={"service": service_call.service}, - ) - - for entry_id in fritzbox_entry_ids: - _LOGGER.debug("Executing service %s", service_call.service) - avm_wrapper: AvmWrapper = hass.data[DOMAIN][entry_id] - if config_entry := hass.config_entries.async_get_entry(entry_id): - await avm_wrapper.service_fritzbox(service_call, config_entry) - else: - _LOGGER.error( - "Executing service %s failed, no config entry found", - service_call.service, - ) - - for service, schema in SERVICE_LIST: - hass.services.async_register(DOMAIN, service, async_call_fritz_service, schema) - - -async def _async_get_configured_avm_device( - hass: HomeAssistant, service_call: ServiceCall -) -> list: - """Get FritzBoxTools class from config entry.""" - - list_entry_id: list = [] - for entry_id in await async_extract_config_entry_ids(hass, service_call): - config_entry = hass.config_entries.async_get_entry(entry_id) - if ( - config_entry - and config_entry.domain == DOMAIN - and config_entry.state == ConfigEntryState.LOADED - ): - list_entry_id.append(entry_id) - return list_entry_id - - -async def async_unload_services(hass: HomeAssistant) -> None: - """Unload services for Fritz integration.""" - - if not hass.data.get(FRITZ_SERVICES): - return - - hass.data[FRITZ_SERVICES] = False - - for service, _ in SERVICE_LIST: - hass.services.async_remove(DOMAIN, service)