Use HassKey in lovelace (#136313)

* Use HassKey in lovelace

* Improve type hints

* docstring

* Rename constant
This commit is contained in:
epenet 2025-01-23 11:26:18 +01:00 committed by GitHub
parent ae65a81188
commit 73bd21e0ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 57 additions and 31 deletions

View File

@ -1,5 +1,6 @@
"""Support for the Lovelace UI."""
from dataclasses import dataclass
import logging
import voluptuous as vol
@ -29,6 +30,7 @@ from .const import ( # noqa: F401
DEFAULT_ICON,
DOMAIN,
EVENT_LOVELACE_UPDATED,
LOVELACE_DATA,
MODE_STORAGE,
MODE_YAML,
RESOURCE_CREATE_FIELDS,
@ -73,6 +75,16 @@ CONFIG_SCHEMA = vol.Schema(
)
@dataclass
class LovelaceData:
"""Dataclass to store information in hass.data."""
mode: str
dashboards: dict[str | None, dashboard.LovelaceConfig]
resources: resources.ResourceStorageCollection
yaml_dashboards: dict[str | None, ConfigType]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Lovelace commands."""
mode = config[DOMAIN][CONF_MODE]
@ -100,7 +112,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
resource_collection = await create_yaml_resource_col(
hass, config[DOMAIN].get(CONF_RESOURCES)
)
hass.data[DOMAIN]["resources"] = resource_collection
hass.data[LOVELACE_DATA].resources = resource_collection
default_config: dashboard.LovelaceConfig
if mode == MODE_YAML:
@ -151,13 +163,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
hass, websocket.websocket_lovelace_delete_config
)
hass.data[DOMAIN] = {
hass.data[LOVELACE_DATA] = LovelaceData(
mode=mode,
# We store a dictionary mapping url_path: config. None is the default.
"mode": mode,
"dashboards": {None: default_config},
"resources": resource_collection,
"yaml_dashboards": config[DOMAIN].get(CONF_DASHBOARDS, {}),
}
dashboards={None: default_config},
resources=resource_collection,
yaml_dashboards=config[DOMAIN].get(CONF_DASHBOARDS, {}),
)
if hass.config.recovery_mode:
return True
@ -168,11 +180,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
if change_type == collection.CHANGE_REMOVED:
frontend.async_remove_panel(hass, url_path)
await hass.data[DOMAIN]["dashboards"].pop(url_path).async_delete()
await hass.data[LOVELACE_DATA].dashboards.pop(url_path).async_delete()
return
if change_type == collection.CHANGE_ADDED:
existing = hass.data[DOMAIN]["dashboards"].get(url_path)
existing = hass.data[LOVELACE_DATA].dashboards.get(url_path)
if existing:
_LOGGER.warning(
@ -182,13 +194,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
)
return
hass.data[DOMAIN]["dashboards"][url_path] = dashboard.LovelaceStorage(
hass.data[LOVELACE_DATA].dashboards[url_path] = dashboard.LovelaceStorage(
hass, item
)
update = False
else:
hass.data[DOMAIN]["dashboards"][url_path].config = item
hass.data[LOVELACE_DATA].dashboards[url_path].config = item
update = True
try:
@ -197,10 +209,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
_LOGGER.warning("Failed to %s panel %s from storage", change_type, url_path)
# Process YAML dashboards
for url_path, dashboard_conf in hass.data[DOMAIN]["yaml_dashboards"].items():
for url_path, dashboard_conf in hass.data[LOVELACE_DATA].yaml_dashboards.items():
# For now always mode=yaml
lovelace_config = dashboard.LovelaceYAML(hass, url_path, dashboard_conf)
hass.data[DOMAIN]["dashboards"][url_path] = lovelace_config
hass.data[LOVELACE_DATA].dashboards[url_path] = lovelace_config
try:
_register_panel(hass, url_path, MODE_YAML, dashboard_conf, False)

View File

@ -2,6 +2,8 @@
from __future__ import annotations
from typing import Any
from pychromecast import Chromecast
from pychromecast.const import CAST_TYPE_CHROMECAST
@ -23,8 +25,7 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.network import NoURLAvailableError, get_url
from .const import DOMAIN, ConfigNotFound
from .dashboard import LovelaceConfig
from .const import DOMAIN, LOVELACE_DATA, ConfigNotFound
DEFAULT_DASHBOARD = "_default_"
@ -76,7 +77,7 @@ async def async_browse_media(
can_expand=False,
)
]
for url_path in hass.data[DOMAIN]["dashboards"]:
for url_path in hass.data[LOVELACE_DATA].dashboards:
if url_path is None:
continue
@ -151,11 +152,13 @@ async def async_play_media(
return True
async def _get_dashboard_info(hass, url_path):
async def _get_dashboard_info(
hass: HomeAssistant, url_path: str | None
) -> dict[str, Any]:
"""Load a dashboard and return info on views."""
if url_path == DEFAULT_DASHBOARD:
url_path = None
dashboard: LovelaceConfig | None = hass.data[DOMAIN]["dashboards"].get(url_path)
dashboard = hass.data[LOVELACE_DATA].dashboards.get(url_path)
if dashboard is None:
raise ValueError("Invalid dashboard specified")
@ -172,7 +175,7 @@ async def _get_dashboard_info(hass, url_path):
url_path = dashboard.url_path
title = config.get("title", url_path) if config else url_path
views = []
views: list[dict[str, Any]] = []
data = {
"title": title,
"url_path": url_path,

View File

@ -1,6 +1,8 @@
"""Constants for Lovelace."""
from typing import Any
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import voluptuous as vol
@ -15,8 +17,13 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import VolDictType
from homeassistant.util import slugify
from homeassistant.util.hass_dict import HassKey
if TYPE_CHECKING:
from . import LovelaceData
DOMAIN = "lovelace"
LOVELACE_DATA: HassKey[LovelaceData] = HassKey(DOMAIN)
DEFAULT_ICON = "hass:view-dashboard"

View File

@ -27,6 +27,7 @@ from .const import (
DOMAIN,
EVENT_LOVELACE_UPDATED,
LOVELACE_CONFIG_FILE,
LOVELACE_DATA,
MODE_STORAGE,
MODE_YAML,
STORAGE_DASHBOARD_CREATE_FIELDS,
@ -315,7 +316,7 @@ class DashboardsCollectionWebSocket(collection.DictStorageCollectionWebsocket):
msg["id"],
[
dashboard.config
for dashboard in hass.data[DOMAIN]["dashboards"].values()
for dashboard in hass.data[LOVELACE_DATA].dashboards.values()
if dashboard.config
],
)

View File

@ -1,12 +1,13 @@
"""Provide info to system health."""
import asyncio
from typing import Any
from homeassistant.components import system_health
from homeassistant.const import CONF_MODE
from homeassistant.core import HomeAssistant, callback
from .const import DOMAIN, MODE_AUTO, MODE_STORAGE, MODE_YAML
from .const import LOVELACE_DATA, MODE_AUTO, MODE_STORAGE, MODE_YAML
@callback
@ -17,15 +18,17 @@ def async_register(
register.async_register_info(system_health_info, "/config/lovelace")
async def system_health_info(hass):
async def system_health_info(hass: HomeAssistant) -> dict[str, Any]:
"""Get info for the info page."""
health_info = {"dashboards": len(hass.data[DOMAIN]["dashboards"])}
health_info.update(await hass.data[DOMAIN]["resources"].async_get_info())
health_info: dict[str, Any] = {
"dashboards": len(hass.data[LOVELACE_DATA].dashboards)
}
health_info.update(await hass.data[LOVELACE_DATA].resources.async_get_info())
dashboards_info = await asyncio.gather(
*(
hass.data[DOMAIN]["dashboards"][dashboard].async_get_info()
for dashboard in hass.data[DOMAIN]["dashboards"]
hass.data[LOVELACE_DATA].dashboards[dashboard].async_get_info()
for dashboard in hass.data[LOVELACE_DATA].dashboards
)
)
@ -39,7 +42,7 @@ async def system_health_info(hass):
else:
health_info[key] = dashboard[key]
if hass.data[DOMAIN][CONF_MODE] == MODE_YAML:
if hass.data[LOVELACE_DATA].mode == MODE_YAML:
health_info[CONF_MODE] = MODE_YAML
elif MODE_STORAGE in modes:
health_info[CONF_MODE] = MODE_STORAGE

View File

@ -13,7 +13,7 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.json import json_fragment
from .const import CONF_URL_PATH, DOMAIN, ConfigNotFound
from .const import CONF_URL_PATH, LOVELACE_DATA, ConfigNotFound
from .dashboard import LovelaceStorage
@ -27,7 +27,7 @@ def _handle_errors(func):
msg: dict[str, Any],
) -> None:
url_path = msg.get(CONF_URL_PATH)
config: LovelaceStorage | None = hass.data[DOMAIN]["dashboards"].get(url_path)
config = hass.data[LOVELACE_DATA].dashboards.get(url_path)
if config is None:
connection.send_error(
@ -74,7 +74,7 @@ async def websocket_lovelace_resources_impl(
This function is called by both Storage and YAML mode WS handlers.
"""
resources = hass.data[DOMAIN]["resources"]
resources = hass.data[LOVELACE_DATA].resources
if hass.config.safe_mode:
connection.send_result(msg["id"], [])