core/homeassistant/components/sabnzbd/__init__.py

168 lines
5.0 KiB
Python

"""Support for monitoring an SABnzbd NZB client."""
from __future__ import annotations
from collections.abc import Callable, Coroutine
import logging
from typing import Any
import voluptuous as vol
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import config_validation as cv
import homeassistant.helpers.issue_registry as ir
from homeassistant.helpers.typing import ConfigType
from .const import (
ATTR_API_KEY,
ATTR_SPEED,
DEFAULT_SPEED_LIMIT,
DOMAIN,
SERVICE_PAUSE,
SERVICE_RESUME,
SERVICE_SET_SPEED,
)
from .coordinator import SabnzbdConfigEntry, SabnzbdUpdateCoordinator
from .helpers import get_client
PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.NUMBER, Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
SERVICES = (
SERVICE_PAUSE,
SERVICE_RESUME,
SERVICE_SET_SPEED,
)
SERVICE_BASE_SCHEMA = vol.Schema(
{
vol.Required(ATTR_API_KEY): cv.string,
}
)
SERVICE_SPEED_SCHEMA = SERVICE_BASE_SCHEMA.extend(
{
vol.Optional(ATTR_SPEED, default=DEFAULT_SPEED_LIMIT): cv.string,
}
)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
@callback
def async_get_entry_for_service_call(
hass: HomeAssistant, call: ServiceCall
) -> SabnzbdConfigEntry:
"""Get the entry ID related to a service call (by device ID)."""
call_data_api_key = call.data[ATTR_API_KEY]
for entry in hass.config_entries.async_entries(DOMAIN):
if entry.data[ATTR_API_KEY] == call_data_api_key:
return entry
raise ValueError(f"No api for API key: {call_data_api_key}")
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the SabNzbd Component."""
@callback
def extract_api(
func: Callable[
[ServiceCall, SabnzbdUpdateCoordinator], Coroutine[Any, Any, None]
],
) -> Callable[[ServiceCall], Coroutine[Any, Any, None]]:
"""Define a decorator to get the correct api for a service call."""
async def wrapper(call: ServiceCall) -> None:
"""Wrap the service function."""
config_entry = async_get_entry_for_service_call(hass, call)
coordinator = config_entry.runtime_data
try:
await func(call, coordinator)
except Exception as err:
raise HomeAssistantError(
f"Error while executing {func.__name__}: {err}"
) from err
return wrapper
@extract_api
async def async_pause_queue(
call: ServiceCall, coordinator: SabnzbdUpdateCoordinator
) -> None:
ir.async_create_issue(
hass,
DOMAIN,
"pause_action_deprecated",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
breaks_in_ha_version="2025.6",
translation_key="pause_action_deprecated",
)
await coordinator.sab_api.pause_queue()
@extract_api
async def async_resume_queue(
call: ServiceCall, coordinator: SabnzbdUpdateCoordinator
) -> None:
ir.async_create_issue(
hass,
DOMAIN,
"resume_action_deprecated",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
breaks_in_ha_version="2025.6",
translation_key="resume_action_deprecated",
)
await coordinator.sab_api.resume_queue()
@extract_api
async def async_set_queue_speed(
call: ServiceCall, coordinator: SabnzbdUpdateCoordinator
) -> None:
ir.async_create_issue(
hass,
DOMAIN,
"set_speed_action_deprecated",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
breaks_in_ha_version="2025.6",
translation_key="set_speed_action_deprecated",
)
speed = call.data.get(ATTR_SPEED)
await coordinator.sab_api.set_speed_limit(speed)
for service, method, schema in (
(SERVICE_PAUSE, async_pause_queue, SERVICE_BASE_SCHEMA),
(SERVICE_RESUME, async_resume_queue, SERVICE_BASE_SCHEMA),
(SERVICE_SET_SPEED, async_set_queue_speed, SERVICE_SPEED_SCHEMA),
):
hass.services.async_register(DOMAIN, service, method, schema=schema)
return True
async def async_setup_entry(hass: HomeAssistant, entry: SabnzbdConfigEntry) -> bool:
"""Set up the SabNzbd Component."""
sab_api = await get_client(hass, entry.data)
if not sab_api:
raise ConfigEntryNotReady
coordinator = SabnzbdUpdateCoordinator(hass, entry, sab_api)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: SabnzbdConfigEntry) -> bool:
"""Unload a Sabnzbd config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)