1 """Support for the Lovelace UI."""
5 import voluptuous
as vol
9 async_hass_config_yaml,
10 async_process_component_and_handle_errors,
21 from .
import dashboard, resources, websocket
23 CONF_ALLOW_SINGLE_WORD,
29 DASHBOARD_BASE_CREATE_FIELDS,
32 EVENT_LOVELACE_UPDATED,
35 RESOURCE_CREATE_FIELDS,
36 RESOURCE_RELOAD_SERVICE_SCHEMA,
38 RESOURCE_UPDATE_FIELDS,
39 SERVICE_RELOAD_RESOURCES,
40 STORAGE_DASHBOARD_CREATE_FIELDS,
41 STORAGE_DASHBOARD_UPDATE_FIELDS,
44 from .system_health
import system_health_info
46 _LOGGER = logging.getLogger(__name__)
48 CONF_DASHBOARDS =
"dashboards"
50 YAML_DASHBOARD_SCHEMA = vol.Schema(
52 **DASHBOARD_BASE_CREATE_FIELDS,
53 vol.Required(CONF_MODE): MODE_YAML,
54 vol.Required(CONF_FILENAME): cv.path,
58 CONFIG_SCHEMA = vol.Schema(
60 vol.Optional(DOMAIN, default={}): vol.Schema(
62 vol.Optional(CONF_MODE, default=MODE_STORAGE): vol.All(
63 vol.Lower, vol.In([MODE_YAML, MODE_STORAGE])
65 vol.Optional(CONF_DASHBOARDS): cv.schema_with_slug_keys(
66 YAML_DASHBOARD_SCHEMA,
67 slug_validator=url_slug,
69 vol.Optional(CONF_RESOURCES): [RESOURCE_SCHEMA],
73 extra=vol.ALLOW_EXTRA,
77 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
78 """Set up the Lovelace commands."""
79 mode = config[DOMAIN][CONF_MODE]
80 yaml_resources = config[DOMAIN].
get(CONF_RESOURCES)
82 frontend.async_register_built_in_panel(hass, DOMAIN, config={
"mode": mode})
85 """Reload yaml resources."""
88 except HomeAssistantError
as err:
95 hass, conf, integration
102 hass, config[DOMAIN].
get(CONF_RESOURCES)
104 hass.data[DOMAIN][
"resources"] = resource_collection
107 if mode == MODE_YAML:
114 SERVICE_RELOAD_RESOURCES,
115 reload_resources_service_handler,
116 schema=RESOURCE_RELOAD_SERVICE_SCHEMA,
120 for command
in (
"lovelace/resources",
"lovelace/resources/list"):
121 websocket_api.async_register_command(
124 websocket.websocket_lovelace_resources,
125 websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
133 if yaml_resources
is not None:
135 "Lovelace is running in storage mode. Define resources via user"
143 "lovelace/resources",
145 RESOURCE_CREATE_FIELDS,
146 RESOURCE_UPDATE_FIELDS,
149 websocket_api.async_register_command(hass, websocket.websocket_lovelace_config)
150 websocket_api.async_register_command(hass, websocket.websocket_lovelace_save_config)
151 websocket_api.async_register_command(
152 hass, websocket.websocket_lovelace_delete_config
155 hass.data[DOMAIN] = {
158 "dashboards": {
None: default_config},
159 "resources": resource_collection,
160 "yaml_dashboards": config[DOMAIN].
get(CONF_DASHBOARDS, {}),
163 if hass.config.recovery_mode:
166 async
def storage_dashboard_changed(change_type, item_id, item):
167 """Handle a storage dashboard change."""
168 url_path = item[CONF_URL_PATH]
170 if change_type == collection.CHANGE_REMOVED:
171 frontend.async_remove_panel(hass, url_path)
172 await hass.data[DOMAIN][
"dashboards"].pop(url_path).async_delete()
175 if change_type == collection.CHANGE_ADDED:
176 existing = hass.data[DOMAIN][
"dashboards"].
get(url_path)
180 "Cannot register panel at %s, it is already defined in %s",
192 hass.data[DOMAIN][
"dashboards"][url_path].config = item
198 _LOGGER.warning(
"Failed to %s panel %s from storage", change_type, url_path)
201 for url_path, dashboard_conf
in hass.data[DOMAIN][
"yaml_dashboards"].items():
204 hass.data[DOMAIN][
"dashboards"][url_path] = lovelace_config
209 _LOGGER.warning(
"Panel url path %s is not unique", url_path)
215 hass.data[DOMAIN][
"dashboards_collection"] = dashboards_collection
217 dashboards_collection.async_add_listener(storage_dashboard_changed)
218 await dashboards_collection.async_load()
221 dashboards_collection,
222 "lovelace/dashboards",
224 STORAGE_DASHBOARD_CREATE_FIELDS,
225 STORAGE_DASHBOARD_UPDATE_FIELDS,
228 def create_map_dashboard():
231 if not onboarding.async_is_onboarded(hass):
232 onboarding.async_add_listener(hass, create_map_dashboard)
238 """Create yaml resources collection."""
239 if yaml_resources
is None:
242 ll_conf = await default_config.async_load(
False)
243 except HomeAssistantError:
246 if CONF_RESOURCES
in ll_conf:
248 "Resources need to be specified in your configuration.yaml. Please"
251 yaml_resources = ll_conf[CONF_RESOURCES]
258 """Register a panel."""
260 "frontend_url_path": url_path,
261 "require_admin": config[CONF_REQUIRE_ADMIN],
262 "config": {
"mode": mode},
266 if config[CONF_SHOW_IN_SIDEBAR]:
267 kwargs[
"sidebar_title"] = config[CONF_TITLE]
268 kwargs[
"sidebar_icon"] = config.get(CONF_ICON, DEFAULT_ICON)
270 frontend.async_register_built_in_panel(hass, DOMAIN, **kwargs)
275 hass, hass.config.language,
"dashboard", {onboarding.DOMAIN}
277 title = translations[
"component.onboarding.dashboard.map.title"]
280 "dashboards_collection"
282 await dashboards_collection.async_create_item(
284 CONF_ALLOW_SINGLE_WORD:
True,
285 CONF_ICON:
"mdi:map",
287 CONF_URL_PATH:
"map",
292 await map_store.async_save({
"strategy": {
"type":
"map"}})
web.Response get(self, web.Request request, str config_key)
def _register_panel(hass, url_path, mode, config, update)
None reload_resources_service_handler(ServiceCall service_call)
bool async_setup(HomeAssistant hass, ConfigType config)
def create_yaml_resource_col(hass, yaml_resources)
def _create_map_dashboard(HomeAssistant hass)
ConfigType|None async_process_component_and_handle_errors(HomeAssistant hass, ConfigType config, Integration integration, bool raise_on_failure=False)
dict async_hass_config_yaml(HomeAssistant hass)
None async_register_admin_service(HomeAssistant hass, str domain, str service, Callable[[ServiceCall], Awaitable[None]|None] service_func, VolSchemaType schema=vol.Schema({}, extra=vol.PREVENT_EXTRA))
dict[str, str] async_get_translations(HomeAssistant hass, str language, str category, Iterable[str]|None integrations=None, bool|None config_flow=None)
Integration async_get_integration(HomeAssistant hass, str domain)