core/homeassistant/components/panel_custom.py

171 lines
5.4 KiB
Python

"""
Register a custom front end panel.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/panel_custom/
"""
import logging
import os
import voluptuous as vol
from homeassistant.loader import bind_hass
import homeassistant.helpers.config_validation as cv
DOMAIN = 'panel_custom'
DEPENDENCIES = ['frontend']
CONF_COMPONENT_NAME = 'name'
CONF_SIDEBAR_TITLE = 'sidebar_title'
CONF_SIDEBAR_ICON = 'sidebar_icon'
CONF_URL_PATH = 'url_path'
CONF_CONFIG = 'config'
CONF_WEBCOMPONENT_PATH = 'webcomponent_path'
CONF_JS_URL = 'js_url'
CONF_MODULE_URL = 'module_url'
CONF_EMBED_IFRAME = 'embed_iframe'
CONF_TRUST_EXTERNAL_SCRIPT = 'trust_external_script'
CONF_URL_EXCLUSIVE_GROUP = 'url_exclusive_group'
MSG_URL_CONFLICT = \
'Pass in only one of webcomponent_path, module_url or js_url'
DEFAULT_EMBED_IFRAME = False
DEFAULT_TRUST_EXTERNAL = False
DEFAULT_ICON = 'mdi:bookmark'
LEGACY_URL = '/api/panel_custom/{}'
PANEL_DIR = 'panels'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.All(cv.ensure_list, [vol.Schema({
vol.Required(CONF_COMPONENT_NAME): cv.string,
vol.Optional(CONF_SIDEBAR_TITLE): cv.string,
vol.Optional(CONF_SIDEBAR_ICON, default=DEFAULT_ICON): cv.icon,
vol.Optional(CONF_URL_PATH): cv.string,
vol.Optional(CONF_CONFIG): dict,
vol.Exclusive(CONF_WEBCOMPONENT_PATH, CONF_URL_EXCLUSIVE_GROUP,
msg=MSG_URL_CONFLICT): cv.string,
vol.Exclusive(CONF_JS_URL, CONF_URL_EXCLUSIVE_GROUP,
msg=MSG_URL_CONFLICT): cv.string,
vol.Exclusive(CONF_MODULE_URL, CONF_URL_EXCLUSIVE_GROUP,
msg=MSG_URL_CONFLICT): cv.string,
vol.Optional(CONF_EMBED_IFRAME,
default=DEFAULT_EMBED_IFRAME): cv.boolean,
vol.Optional(CONF_TRUST_EXTERNAL_SCRIPT,
default=DEFAULT_TRUST_EXTERNAL): cv.boolean,
})])
}, extra=vol.ALLOW_EXTRA)
_LOGGER = logging.getLogger(__name__)
@bind_hass
async def async_register_panel(
hass,
# The url to serve the panel
frontend_url_path,
# The webcomponent name that loads your panel
webcomponent_name,
# Title/icon for sidebar
sidebar_title=None,
sidebar_icon=None,
# HTML source of your panel
html_url=None,
# JS source of your panel
js_url=None,
# JS module of your panel
module_url=None,
# If your panel should be run inside an iframe
embed_iframe=DEFAULT_EMBED_IFRAME,
# Should user be asked for confirmation when loading external source
trust_external=DEFAULT_TRUST_EXTERNAL,
# Configuration to be passed to the panel
config=None):
"""Register a new custom panel."""
if js_url is None and html_url is None and module_url is None:
raise ValueError('Either js_url, module_url or html_url is required.')
elif (js_url and html_url) or (module_url and html_url):
raise ValueError('Pass in only one of JS url, Module url or HTML url.')
if config is not None and not isinstance(config, dict):
raise ValueError('Config needs to be a dictionary.')
custom_panel_config = {
'name': webcomponent_name,
'embed_iframe': embed_iframe,
'trust_external': trust_external,
}
if js_url is not None:
custom_panel_config['js_url'] = js_url
if module_url is not None:
custom_panel_config['module_url'] = module_url
if html_url is not None:
custom_panel_config['html_url'] = html_url
if config is not None:
# Make copy because we're mutating it
config = dict(config)
else:
config = {}
config['_panel_custom'] = custom_panel_config
await hass.components.frontend.async_register_built_in_panel(
component_name='custom',
sidebar_title=sidebar_title,
sidebar_icon=sidebar_icon,
frontend_url_path=frontend_url_path,
config=config
)
async def async_setup(hass, config):
"""Initialize custom panel."""
success = False
for panel in config.get(DOMAIN):
name = panel[CONF_COMPONENT_NAME]
kwargs = {
'webcomponent_name': panel[CONF_COMPONENT_NAME],
'frontend_url_path': panel.get(CONF_URL_PATH, name),
'sidebar_title': panel.get(CONF_SIDEBAR_TITLE),
'sidebar_icon': panel.get(CONF_SIDEBAR_ICON),
'config': panel.get(CONF_CONFIG),
'trust_external': panel[CONF_TRUST_EXTERNAL_SCRIPT],
'embed_iframe': panel[CONF_EMBED_IFRAME],
}
panel_path = panel.get(CONF_WEBCOMPONENT_PATH)
if panel_path is None:
panel_path = hass.config.path(
PANEL_DIR, '{}.html'.format(name))
if CONF_JS_URL in panel:
kwargs['js_url'] = panel[CONF_JS_URL]
elif CONF_MODULE_URL in panel:
kwargs['module_url'] = panel[CONF_MODULE_URL]
elif not await hass.async_add_job(os.path.isfile, panel_path):
_LOGGER.error('Unable to find webcomponent for %s: %s',
name, panel_path)
continue
else:
url = LEGACY_URL.format(name)
hass.http.register_static_path(url, panel_path)
kwargs['html_url'] = url
await async_register_panel(hass, **kwargs)
success = True
return success