1 """Data for Hass.io."""
3 from __future__
import annotations
6 from collections
import defaultdict
8 from typing
import TYPE_CHECKING, Any
10 from aiohasupervisor
import SupervisorError
11 from aiohasupervisor.models
import StoreInfo
35 DATA_ADDONS_CHANGELOGS,
47 DATA_KEY_SUPERVISOR_ISSUES,
52 DATA_SUPERVISOR_STATS,
54 HASSIO_UPDATE_INTERVAL,
55 REQUEST_REFRESH_DELAY,
57 SupervisorEntityModel,
59 from .handler
import HassIO, HassioAPIError, get_supervisor_client
62 from .issues
import SupervisorIssues
64 _LOGGER = logging.getLogger(__name__)
69 def get_info(hass: HomeAssistant) -> dict[str, Any] |
None:
70 """Return generic information from Supervisor.
74 return hass.data.get(DATA_INFO)
80 """Return generic host information.
84 return hass.data.get(DATA_HOST_INFO)
89 def get_store(hass: HomeAssistant) -> dict[str, Any] |
None:
90 """Return store information.
94 return hass.data.get(DATA_STORE)
100 """Return Supervisor information.
104 return hass.data.get(DATA_SUPERVISOR_INFO)
110 """Return Host Network information.
114 return hass.data.get(DATA_NETWORK_INFO)
120 """Return Addons info.
124 return hass.data.get(DATA_ADDONS_INFO)
130 """Return Addons stats.
134 return hass.data.get(DATA_ADDONS_STATS)
or {}
140 """Return core stats.
144 return hass.data.get(DATA_CORE_STATS)
or {}
150 """Return supervisor stats.
154 return hass.data.get(DATA_SUPERVISOR_STATS)
or {}
160 """Return Addons changelogs.
164 return hass.data.get(DATA_ADDONS_CHANGELOGS)
170 """Return OS information.
174 return hass.data.get(DATA_OS_INFO)
180 """Return Home Assistant Core information from Supervisor.
184 return hass.data.get(DATA_CORE_INFO)
190 """Return Supervisor issues info.
194 return hass.data.get(DATA_KEY_SUPERVISOR_ISSUES)
199 entry_id: str, dev_reg: dr.DeviceRegistry, addons: list[dict[str, Any]]
201 """Register addons in the device registry."""
204 identifiers={(DOMAIN, addon[ATTR_SLUG])},
205 model=SupervisorEntityModel.ADDON,
206 sw_version=addon[ATTR_VERSION],
207 name=addon[ATTR_NAME],
208 entry_type=dr.DeviceEntryType.SERVICE,
209 configuration_url=f
"homeassistant://hassio/addon/{addon[ATTR_SLUG]}",
211 if manufacturer := addon.get(ATTR_REPOSITORY)
or addon.get(ATTR_URL):
212 params[ATTR_MANUFACTURER] = manufacturer
213 dev_reg.async_get_or_create(config_entry_id=entry_id, **params)
218 entry_id: str, dev_reg: dr.DeviceRegistry, os_dict: dict[str, Any]
220 """Register OS in the device registry."""
222 identifiers={(DOMAIN,
"OS")},
223 manufacturer=
"Home Assistant",
224 model=SupervisorEntityModel.OS,
225 sw_version=os_dict[ATTR_VERSION],
226 name=
"Home Assistant Operating System",
227 entry_type=dr.DeviceEntryType.SERVICE,
229 dev_reg.async_get_or_create(config_entry_id=entry_id, **params)
235 dev_reg: dr.DeviceRegistry,
237 """Register host in the device registry."""
239 identifiers={(DOMAIN,
"host")},
240 manufacturer=
"Home Assistant",
241 model=SupervisorEntityModel.HOST,
242 name=
"Home Assistant Host",
243 entry_type=dr.DeviceEntryType.SERVICE,
245 dev_reg.async_get_or_create(config_entry_id=entry_id, **params)
251 dev_reg: dr.DeviceRegistry,
252 core_dict: dict[str, Any],
254 """Register OS in the device registry."""
256 identifiers={(DOMAIN,
"core")},
257 manufacturer=
"Home Assistant",
258 model=SupervisorEntityModel.CORE,
259 sw_version=core_dict[ATTR_VERSION],
260 name=
"Home Assistant Core",
261 entry_type=dr.DeviceEntryType.SERVICE,
263 dev_reg.async_get_or_create(config_entry_id=entry_id, **params)
269 dev_reg: dr.DeviceRegistry,
270 supervisor_dict: dict[str, Any],
272 """Register OS in the device registry."""
274 identifiers={(DOMAIN,
"supervisor")},
275 manufacturer=
"Home Assistant",
276 model=SupervisorEntityModel.SUPERVIOSR,
277 sw_version=supervisor_dict[ATTR_VERSION],
278 name=
"Home Assistant Supervisor",
279 entry_type=dr.DeviceEntryType.SERVICE,
281 dev_reg.async_get_or_create(config_entry_id=entry_id, **params)
286 dev_reg: dr.DeviceRegistry, addons: set[str]
288 """Remove addons from the device registry."""
289 for addon_slug
in addons:
290 if dev := dev_reg.async_get_device(identifiers={(DOMAIN, addon_slug)}):
291 dev_reg.async_remove_device(dev.id)
295 """Class to retrieve Hass.io status."""
298 self, hass: HomeAssistant, config_entry: ConfigEntry, dev_reg: dr.DeviceRegistry
300 """Initialize coordinator."""
305 update_interval=HASSIO_UPDATE_INTERVAL,
310 hass, _LOGGER, cooldown=REQUEST_REFRESH_DELAY, immediate=
False
313 self.hassio: HassIO = hass.data[DOMAIN]
318 self._container_updates: defaultdict[str, dict[str, set[str]]] = defaultdict(
319 lambda: defaultdict(set)
324 """Update data via library."""
325 is_first_update =
not self.
datadatadata
329 except HassioAPIError
as err:
330 raise UpdateFailed(f
"Error on Supervisor API: {err}")
from err
332 new_data: dict[str, Any] = {}
342 for repo
in StoreInfo.from_dict(store_data).repositories
347 new_data[DATA_KEY_ADDONS] = {
350 **((addons_stats
or {}).
get(addon[ATTR_SLUG])
or {}),
351 ATTR_AUTO_UPDATE: (addons_info.get(addon[ATTR_SLUG])
or {}).
get(
352 ATTR_AUTO_UPDATE,
False
354 ATTR_CHANGELOG: (addons_changelogs
or {}).
get(addon[ATTR_SLUG]),
355 ATTR_REPOSITORY: repositories.get(
356 addon.get(ATTR_REPOSITORY), addon.get(ATTR_REPOSITORY,
"")
359 for addon
in supervisor_info.get(
"addons", [])
364 new_data[DATA_KEY_CORE] = {
368 new_data[DATA_KEY_SUPERVISOR] = {
377 self.
entry_identry_id, self.
dev_regdev_reg, new_data[DATA_KEY_ADDONS].values()
383 self.
entry_identry_id, self.
dev_regdev_reg, new_data[DATA_KEY_SUPERVISOR]
392 supervisor_addon_devices = {
393 list(device.identifiers)[0][1]
394 for device
in self.
dev_regdev_reg.devices.get_devices_for_config_entry_id(
397 if device.model == SupervisorEntityModel.ADDON
399 if stale_addons := supervisor_addon_devices - set(new_data[DATA_KEY_ADDONS]):
403 dev := self.
dev_regdev_reg.async_get_device(identifiers={(DOMAIN,
"OS")})
406 self.
dev_regdev_reg.async_remove_device(dev.id)
411 if self.
datadatadata
and set(new_data[DATA_KEY_ADDONS]) - set(
414 self.
hasshass.async_create_task(
415 self.
hasshass.config_entries.async_reload(self.
entry_identry_id)
422 """Force update of the supervisor info."""
427 """Force update of the addon info."""
428 container_updates = self._container_updates
430 data = self.
hasshass.data
433 DATA_INFO: hassio.get_info(),
434 DATA_CORE_INFO: hassio.get_core_info(),
435 DATA_SUPERVISOR_INFO: hassio.get_supervisor_info(),
436 DATA_OS_INFO: hassio.get_os_info(),
438 if CONTAINER_STATS
in container_updates[CORE_CONTAINER]:
439 updates[DATA_CORE_STATS] = hassio.get_core_stats()
440 if CONTAINER_STATS
in container_updates[SUPERVISOR_CONTAINER]:
441 updates[DATA_SUPERVISOR_STATS] = hassio.get_supervisor_stats()
443 results = await asyncio.gather(*updates.values())
444 for key, result
in zip(updates, results, strict=
False):
447 _addon_data = data[DATA_SUPERVISOR_INFO].
get(
"addons", [])
448 all_addons: list[str] = []
449 started_addons: list[str] = []
450 for addon
in _addon_data:
451 slug = addon[ATTR_SLUG]
452 all_addons.append(slug)
453 if addon[ATTR_STATE] == ATTR_STARTED:
454 started_addons.append(slug)
466 for data_key, update_func, enabled_key, wanted_addons, needs_first_update
in (
475 DATA_ADDONS_CHANGELOGS,
489 container_data: dict[str, Any] = data.setdefault(data_key, {})
490 container_data.update(
492 await asyncio.gather(
495 for slug
in wanted_addons
496 if (first_update
and needs_first_update)
497 or enabled_key
in container_updates[slug]
504 """Update single addon stats."""
507 except SupervisorError
as err:
508 _LOGGER.warning(
"Could not fetch stats for %s: %s", slug, err)
510 return (slug, stats.to_dict())
513 """Return the changelog for an add-on."""
515 changelog = await self.
supervisor_clientsupervisor_client.store.addon_changelog(slug)
516 except SupervisorError
as err:
517 _LOGGER.warning(
"Could not fetch changelog for %s: %s", slug, err)
519 return (slug, changelog)
522 """Return the info for an add-on."""
525 except SupervisorError
as err:
526 _LOGGER.warning(
"Could not fetch info for %s: %s", slug, err)
529 info_dict = info.to_dict()
530 info_dict[
"hassio_api"] = info_dict.pop(
"supervisor_api")
531 info_dict[
"hassio_role"] = info_dict.pop(
"supervisor_role")
532 return (slug, info_dict)
536 self, slug: str, entity_id: str, types: set[str]
538 """Enable updates for an add-on."""
539 enabled_updates = self._container_updates[slug]
541 enabled_updates[key].
add(entity_id)
544 def _remove() -> None:
546 enabled_updates[key].
remove(entity_id)
552 log_failures: bool =
True,
553 raise_on_auth_failed: bool =
False,
554 scheduled: bool =
False,
555 raise_on_entry_error: bool =
False,
558 if not scheduled
and not raise_on_auth_failed:
567 except SupervisorError
as err:
568 _LOGGER.warning(
"Error on Supervisor API: %s", err)
571 log_failures, raise_on_auth_failed, scheduled, raise_on_entry_error
None force_info_update_supervisor(self)
dict[str, Any] _async_update_data(self)
tuple[str, dict[str, Any]|None] _update_addon_info(self, str slug)
CALLBACK_TYPE async_enable_container_updates(self, str slug, str entity_id, set[str] types)
None force_data_refresh(self, bool first_update)
tuple[str, dict[str, Any]|None] _update_addon_stats(self, str slug)
None _async_refresh(self, bool log_failures=True, bool raise_on_auth_failed=False, bool scheduled=False, bool raise_on_entry_error=False)
tuple[str, str|None] _update_addon_changelog(self, str slug)
None __init__(self, HomeAssistant hass, ConfigEntry config_entry, dr.DeviceRegistry dev_reg)
bool add(self, _T matcher)
bool remove(self, _T matcher)
web.Response get(self, web.Request request, str config_key)
dict[str, dict[str, Any]]|None get_addons_info(HomeAssistant hass)
None async_register_host_in_dev_reg(str entry_id, dr.DeviceRegistry dev_reg)
None async_register_core_in_dev_reg(str entry_id, dr.DeviceRegistry dev_reg, dict[str, Any] core_dict)
dict[str, Any]|None get_supervisor_info(HomeAssistant hass)
dict[str, Any]|None get_store(HomeAssistant hass)
dict[str, Any] get_addons_stats(HomeAssistant hass)
dict[str, Any]|None get_core_info(HomeAssistant hass)
None async_register_supervisor_in_dev_reg(str entry_id, dr.DeviceRegistry dev_reg, dict[str, Any] supervisor_dict)
dict[str, Any]|None get_info(HomeAssistant hass)
dict[str, Any]|None get_host_info(HomeAssistant hass)
dict[str, Any]|None get_network_info(HomeAssistant hass)
def get_addons_changelogs(HomeAssistant hass)
SupervisorIssues|None get_issues_info(HomeAssistant hass)
None async_remove_addons_from_dev_reg(dr.DeviceRegistry dev_reg, set[str] addons)
dict[str, Any]|None get_os_info(HomeAssistant hass)
dict[str, Any] get_core_stats(HomeAssistant hass)
None async_register_addons_in_dev_reg(str entry_id, dr.DeviceRegistry dev_reg, list[dict[str, Any]] addons)
None async_register_os_in_dev_reg(str entry_id, dr.DeviceRegistry dev_reg, dict[str, Any] os_dict)
dict[str, Any] get_supervisor_stats(HomeAssistant hass)
SupervisorClient get_supervisor_client(HomeAssistant hass)