"""The Open Thread Border Router integration.""" from __future__ import annotations from collections.abc import Callable, Coroutine import dataclasses from functools import wraps from typing import Any, Concatenate, ParamSpec, TypeVar import python_otbr_api from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import ConfigType from . import websocket_api from .const import DOMAIN _R = TypeVar("_R") _P = ParamSpec("_P") def _handle_otbr_error( func: Callable[Concatenate[OTBRData, _P], Coroutine[Any, Any, _R]] ) -> Callable[Concatenate[OTBRData, _P], Coroutine[Any, Any, _R]]: """Handle OTBR errors.""" @wraps(func) async def _func(self: OTBRData, *args: _P.args, **kwargs: _P.kwargs) -> _R: try: return await func(self, *args, **kwargs) except python_otbr_api.OTBRError as exc: raise HomeAssistantError("Failed to call OTBR API") from exc return _func @dataclasses.dataclass class OTBRData: """Container for OTBR data.""" url: str api: python_otbr_api.OTBR @_handle_otbr_error async def get_active_dataset_tlvs(self) -> bytes | None: """Get current active operational dataset in TLVS format, or None.""" return await self.api.get_active_dataset_tlvs() async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Open Thread Border Router component.""" websocket_api.async_setup(hass) return True async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up an Open Thread Border Router config entry.""" api = python_otbr_api.OTBR(entry.data["url"], async_get_clientsession(hass), 10) hass.data[DOMAIN] = OTBRData(entry.data["url"], api) return True async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" hass.data.pop(DOMAIN) return True async def async_get_active_dataset_tlvs(hass: HomeAssistant) -> bytes | None: """Get current active operational dataset in TLVS format, or None. Returns None if there is no active operational dataset. Raises if the http status is 400 or higher or if the response is invalid. """ if DOMAIN not in hass.data: raise HomeAssistantError("OTBR API not available") data: OTBRData = hass.data[DOMAIN] return await data.get_active_dataset_tlvs()