"""Data update coordinator for the Nextcloud integration.""" import logging from typing import Any from nextcloudmonitor import NextcloudMonitor, NextcloudMonitorError from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_URL from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DEFAULT_SCAN_INTERVAL, DOMAIN _LOGGER = logging.getLogger(__name__) class NextcloudDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]): """Nextcloud data update coordinator.""" def __init__( self, hass: HomeAssistant, ncm: NextcloudMonitor, entry: ConfigEntry ) -> None: """Initialize the Nextcloud coordinator.""" self.ncm = ncm self.url = entry.data[CONF_URL] super().__init__( hass, _LOGGER, name=self.url, update_interval=DEFAULT_SCAN_INTERVAL, ) # Use recursion to create list of sensors & values based on nextcloud api data def _get_data_points( self, api_data: dict, key_path: str = "", leaf: bool = False ) -> dict[str, Any]: """Use Recursion to discover data-points and values. Get dictionary of data-points by recursing through dict returned by api until the dictionary value does not contain another dictionary and use the resulting path of dictionary keys and resulting value as the name/value for the data-point. returns: dictionary of data-point/values """ result = {} for key, value in api_data.items(): if isinstance(value, dict): if leaf: key_path = f"{key}_" if not leaf: key_path += f"{key}_" leaf = True result.update(self._get_data_points(value, key_path, leaf)) else: result[f"{DOMAIN}_{key_path}{key}"] = value leaf = False return result async def _async_update_data(self) -> dict[str, Any]: """Fetch all Nextcloud data.""" def _update_data() -> None: try: self.ncm.update() except NextcloudMonitorError as ex: raise UpdateFailed from ex await self.hass.async_add_executor_job(_update_data) return self._get_data_points(self.ncm.data)