Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Register a custom front end panel."""
2 
3 from __future__ import annotations
4 
5 import logging
6 
7 import voluptuous as vol
8 
9 from homeassistant.components import frontend
10 from homeassistant.core import HomeAssistant
12 from homeassistant.helpers.typing import ConfigType
13 from homeassistant.loader import bind_hass
14 
15 _LOGGER = logging.getLogger(__name__)
16 
17 DOMAIN = "panel_custom"
18 CONF_COMPONENT_NAME = "name"
19 CONF_SIDEBAR_TITLE = "sidebar_title"
20 CONF_SIDEBAR_ICON = "sidebar_icon"
21 CONF_URL_PATH = "url_path"
22 CONF_CONFIG = "config"
23 CONF_JS_URL = "js_url"
24 CONF_MODULE_URL = "module_url"
25 CONF_EMBED_IFRAME = "embed_iframe"
26 CONF_TRUST_EXTERNAL_SCRIPT = "trust_external_script"
27 CONF_URL_EXCLUSIVE_GROUP = "url_exclusive_group"
28 CONF_REQUIRE_ADMIN = "require_admin"
29 
30 DEFAULT_EMBED_IFRAME = False
31 DEFAULT_TRUST_EXTERNAL = False
32 
33 DEFAULT_ICON = "mdi:bookmark"
34 LEGACY_URL = "/api/panel_custom/{}"
35 
36 PANEL_DIR = "panels"
37 
38 
39 CONFIG_SCHEMA = vol.Schema(
40  {
41  DOMAIN: vol.All(
42  cv.ensure_list,
43  [
44  vol.Schema(
45  {
46  vol.Required(CONF_COMPONENT_NAME): cv.string,
47  vol.Optional(CONF_SIDEBAR_TITLE): cv.string,
48  vol.Optional(CONF_SIDEBAR_ICON, default=DEFAULT_ICON): cv.icon,
49  vol.Optional(CONF_URL_PATH): cv.string,
50  vol.Optional(CONF_CONFIG): dict,
51  vol.Optional(
52  CONF_JS_URL,
53  ): cv.string,
54  vol.Optional(
55  CONF_MODULE_URL,
56  ): cv.string,
57  vol.Optional(
58  CONF_EMBED_IFRAME, default=DEFAULT_EMBED_IFRAME
59  ): cv.boolean,
60  vol.Optional(
61  CONF_TRUST_EXTERNAL_SCRIPT,
62  default=DEFAULT_TRUST_EXTERNAL,
63  ): cv.boolean,
64  vol.Optional(CONF_REQUIRE_ADMIN, default=False): cv.boolean,
65  }
66  ),
67  ],
68  )
69  },
70  extra=vol.ALLOW_EXTRA,
71 )
72 
73 
74 @bind_hass
76  hass: HomeAssistant,
77  # The url to serve the panel
78  frontend_url_path: str,
79  # The webcomponent name that loads your panel
80  webcomponent_name: str,
81  # Title/icon for sidebar
82  sidebar_title: str | None = None,
83  sidebar_icon: str | None = None,
84  # JS source of your panel
85  js_url: str | None = None,
86  # JS module of your panel
87  module_url: str | None = None,
88  # If your panel should be run inside an iframe
89  embed_iframe: bool = DEFAULT_EMBED_IFRAME,
90  # Should user be asked for confirmation when loading external source
91  trust_external: bool = DEFAULT_TRUST_EXTERNAL,
92  # Configuration to be passed to the panel
93  config: ConfigType | None = None,
94  # If your panel should only be shown to admin users
95  require_admin: bool = False,
96  # If your panel is used to configure an integration, needs the domain of the integration
97  config_panel_domain: str | None = None,
98 ) -> None:
99  """Register a new custom panel."""
100  if js_url is None and module_url is None:
101  raise ValueError("Either js_url, module_url or html_url is required.")
102  if config is not None and not isinstance(config, dict):
103  raise ValueError("Config needs to be a dictionary.")
104 
105  custom_panel_config = {
106  "name": webcomponent_name,
107  "embed_iframe": embed_iframe,
108  "trust_external": trust_external,
109  }
110 
111  if js_url is not None:
112  custom_panel_config["js_url"] = js_url
113 
114  if module_url is not None:
115  custom_panel_config["module_url"] = module_url
116 
117  if config is not None:
118  # Make copy because we're mutating it
119  config = dict(config)
120  else:
121  config = {}
122 
123  config["_panel_custom"] = custom_panel_config
124 
125  frontend.async_register_built_in_panel(
126  hass,
127  component_name="custom",
128  sidebar_title=sidebar_title,
129  sidebar_icon=sidebar_icon,
130  frontend_url_path=frontend_url_path,
131  config=config,
132  require_admin=require_admin,
133  config_panel_domain=config_panel_domain,
134  )
135 
136 
137 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
138  """Initialize custom panel."""
139  if DOMAIN not in config:
140  return True
141 
142  for panel in config[DOMAIN]:
143  name = panel[CONF_COMPONENT_NAME]
144 
145  kwargs = {
146  "webcomponent_name": panel[CONF_COMPONENT_NAME],
147  "frontend_url_path": panel.get(CONF_URL_PATH, name),
148  "sidebar_title": panel.get(CONF_SIDEBAR_TITLE),
149  "sidebar_icon": panel.get(CONF_SIDEBAR_ICON),
150  "config": panel.get(CONF_CONFIG),
151  "trust_external": panel[CONF_TRUST_EXTERNAL_SCRIPT],
152  "embed_iframe": panel[CONF_EMBED_IFRAME],
153  "require_admin": panel[CONF_REQUIRE_ADMIN],
154  }
155 
156  if CONF_JS_URL in panel:
157  kwargs["js_url"] = panel[CONF_JS_URL]
158 
159  if CONF_MODULE_URL in panel:
160  kwargs["module_url"] = panel[CONF_MODULE_URL]
161 
162  try:
163  await async_register_panel(hass, **kwargs)
164  except ValueError as err:
165  _LOGGER.error(
166  "Unable to register panel %s: %s",
167  panel.get(CONF_SIDEBAR_TITLE, name),
168  err,
169  )
170 
171  return True
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:137
None async_register_panel(HomeAssistant hass, str frontend_url_path, str webcomponent_name, str|None sidebar_title=None, str|None sidebar_icon=None, str|None js_url=None, str|None module_url=None, bool embed_iframe=DEFAULT_EMBED_IFRAME, bool trust_external=DEFAULT_TRUST_EXTERNAL, ConfigType|None config=None, bool require_admin=False, str|None config_panel_domain=None)
Definition: __init__.py:98