hass-core/homeassistant/components/lovelace/__init__.py

166 lines
5.2 KiB
Python
Raw Normal View History

"""Support for the Lovelace UI."""
import logging
from typing import Any
import voluptuous as vol
from homeassistant.components import frontend
from homeassistant.const import CONF_FILENAME, CONF_ICON
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.util import sanitize_filename, slugify
from . import dashboard, resources, websocket
from .const import (
CONF_RESOURCES,
DOMAIN,
LOVELACE_CONFIG_FILE,
MODE_STORAGE,
MODE_YAML,
RESOURCE_SCHEMA,
)
_LOGGER = logging.getLogger(__name__)
2019-07-31 12:25:30 -07:00
CONF_MODE = "mode"
CONF_DASHBOARDS = "dashboards"
CONF_SIDEBAR = "sidebar"
CONF_TITLE = "title"
CONF_REQUIRE_ADMIN = "require_admin"
DASHBOARD_BASE_SCHEMA = vol.Schema(
{
vol.Optional(CONF_REQUIRE_ADMIN, default=False): cv.boolean,
vol.Optional(CONF_SIDEBAR): {
vol.Required(CONF_ICON): cv.icon,
vol.Required(CONF_TITLE): cv.string,
},
}
)
YAML_DASHBOARD_SCHEMA = DASHBOARD_BASE_SCHEMA.extend(
{
vol.Required(CONF_MODE): MODE_YAML,
vol.Required(CONF_FILENAME): vol.All(cv.string, sanitize_filename),
}
)
def url_slug(value: Any) -> str:
"""Validate value is a valid url slug."""
if value is None:
raise vol.Invalid("Slug should not be None")
str_value = str(value)
slg = slugify(str_value, separator="-")
if str_value == slg:
return str_value
raise vol.Invalid(f"invalid slug {value} (try {slg})")
2019-07-31 12:25:30 -07:00
CONFIG_SCHEMA = vol.Schema(
{
vol.Optional(DOMAIN, default={}): vol.Schema(
2019-07-31 12:25:30 -07:00
{
vol.Optional(CONF_MODE, default=MODE_STORAGE): vol.All(
vol.Lower, vol.In([MODE_YAML, MODE_STORAGE])
),
vol.Optional(CONF_DASHBOARDS): cv.schema_with_slug_keys(
YAML_DASHBOARD_SCHEMA, slug_validator=url_slug,
),
vol.Optional(CONF_RESOURCES): [RESOURCE_SCHEMA],
2019-07-31 12:25:30 -07:00
}
)
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass, config):
"""Set up the Lovelace commands."""
# Pass in default to `get` because defaults not set if loaded as dep
mode = config[DOMAIN][CONF_MODE]
yaml_resources = config[DOMAIN].get(CONF_RESOURCES)
frontend.async_register_built_in_panel(hass, DOMAIN, config={"mode": mode})
if mode == MODE_YAML:
default_config = dashboard.LovelaceYAML(hass, None, LOVELACE_CONFIG_FILE)
if yaml_resources is None:
try:
ll_conf = await default_config.async_load(False)
except HomeAssistantError:
pass
else:
if CONF_RESOURCES in ll_conf:
_LOGGER.warning(
"Resources need to be specified in your configuration.yaml. Please see the docs."
)
yaml_resources = ll_conf[CONF_RESOURCES]
resource_collection = resources.ResourceYAMLCollection(yaml_resources or [])
else:
default_config = dashboard.LovelaceStorage(hass, None)
if yaml_resources is not None:
_LOGGER.warning(
"Lovelace is running in storage mode. Define resources via user interface"
)
resource_collection = resources.ResourceStorageCollection(hass, default_config)
hass.components.websocket_api.async_register_command(
websocket.websocket_lovelace_config
)
hass.components.websocket_api.async_register_command(
websocket.websocket_lovelace_save_config
)
hass.components.websocket_api.async_register_command(
websocket.websocket_lovelace_delete_config
)
hass.components.websocket_api.async_register_command(
websocket.websocket_lovelace_resources
2019-07-31 12:25:30 -07:00
)
2019-07-31 12:25:30 -07:00
hass.components.system_health.async_register_info(DOMAIN, system_health_info)
2019-01-30 12:57:56 -08:00
hass.data[DOMAIN] = {
# We store a dictionary mapping url_path: config. None is the default.
"dashboards": {None: default_config},
"resources": resource_collection,
}
if hass.config.safe_mode or CONF_DASHBOARDS not in config[DOMAIN]:
return True
for url_path, dashboard_conf in config[DOMAIN][CONF_DASHBOARDS].items():
# For now always mode=yaml
config = dashboard.LovelaceYAML(hass, url_path, dashboard_conf[CONF_FILENAME])
hass.data[DOMAIN]["dashboards"][url_path] = config
kwargs = {
"hass": hass,
"component_name": DOMAIN,
"frontend_url_path": url_path,
"require_admin": dashboard_conf[CONF_REQUIRE_ADMIN],
"config": {"mode": dashboard_conf[CONF_MODE]},
}
if CONF_SIDEBAR in dashboard_conf:
kwargs["sidebar_title"] = dashboard_conf[CONF_SIDEBAR][CONF_TITLE]
kwargs["sidebar_icon"] = dashboard_conf[CONF_SIDEBAR][CONF_ICON]
2019-07-31 12:25:30 -07:00
try:
frontend.async_register_built_in_panel(**kwargs)
except ValueError:
_LOGGER.warning("Panel url path %s is not unique", url_path)
return True
2019-01-30 12:57:56 -08:00
async def system_health_info(hass):
"""Get info for the info page."""
return await hass.data[DOMAIN]["dashboards"][None].async_get_info()