2020-02-25 19:18:21 +00:00
|
|
|
"""Websocket API for Lovelace."""
|
|
|
|
from functools import wraps
|
|
|
|
|
|
|
|
import voluptuous as vol
|
|
|
|
|
|
|
|
from homeassistant.components import websocket_api
|
2020-02-28 20:43:17 +00:00
|
|
|
from homeassistant.core import callback
|
2020-02-25 19:18:21 +00:00
|
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
|
|
from homeassistant.helpers import config_validation as cv
|
|
|
|
|
|
|
|
from .const import CONF_URL_PATH, DOMAIN, ConfigNotFound
|
|
|
|
|
|
|
|
|
|
|
|
def _handle_errors(func):
|
|
|
|
"""Handle error with WebSocket calls."""
|
|
|
|
|
|
|
|
@wraps(func)
|
|
|
|
async def send_with_error_handling(hass, connection, msg):
|
|
|
|
url_path = msg.get(CONF_URL_PATH)
|
|
|
|
config = hass.data[DOMAIN]["dashboards"].get(url_path)
|
|
|
|
|
|
|
|
if config is None:
|
|
|
|
connection.send_error(
|
|
|
|
msg["id"], "config_not_found", f"Unknown config specified: {url_path}"
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
error = None
|
|
|
|
try:
|
|
|
|
result = await func(hass, connection, msg, config)
|
|
|
|
except ConfigNotFound:
|
|
|
|
error = "config_not_found", "No config found."
|
|
|
|
except HomeAssistantError as err:
|
|
|
|
error = "error", str(err)
|
|
|
|
|
|
|
|
if error is not None:
|
|
|
|
connection.send_error(msg["id"], *error)
|
|
|
|
return
|
|
|
|
|
|
|
|
if msg is not None:
|
|
|
|
await connection.send_big_result(msg["id"], result)
|
|
|
|
else:
|
|
|
|
connection.send_result(msg["id"], result)
|
|
|
|
|
|
|
|
return send_with_error_handling
|
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.async_response
|
|
|
|
@websocket_api.websocket_command({"type": "lovelace/resources"})
|
|
|
|
async def websocket_lovelace_resources(hass, connection, msg):
|
|
|
|
"""Send Lovelace UI resources over WebSocket configuration."""
|
|
|
|
resources = hass.data[DOMAIN]["resources"]
|
|
|
|
|
|
|
|
if not resources.loaded:
|
|
|
|
await resources.async_load()
|
|
|
|
resources.loaded = True
|
|
|
|
|
|
|
|
connection.send_result(msg["id"], resources.async_items())
|
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.async_response
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
"type": "lovelace/config",
|
|
|
|
vol.Optional("force", default=False): bool,
|
|
|
|
vol.Optional(CONF_URL_PATH): vol.Any(None, cv.string),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@_handle_errors
|
|
|
|
async def websocket_lovelace_config(hass, connection, msg, config):
|
|
|
|
"""Send Lovelace UI config over WebSocket configuration."""
|
|
|
|
return await config.async_load(msg["force"])
|
|
|
|
|
|
|
|
|
2020-03-31 09:43:21 +00:00
|
|
|
@websocket_api.require_admin
|
2020-02-25 19:18:21 +00:00
|
|
|
@websocket_api.async_response
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
"type": "lovelace/config/save",
|
|
|
|
"config": vol.Any(str, dict),
|
|
|
|
vol.Optional(CONF_URL_PATH): vol.Any(None, cv.string),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@_handle_errors
|
|
|
|
async def websocket_lovelace_save_config(hass, connection, msg, config):
|
|
|
|
"""Save Lovelace UI configuration."""
|
|
|
|
await config.async_save(msg["config"])
|
|
|
|
|
|
|
|
|
2020-03-31 09:43:21 +00:00
|
|
|
@websocket_api.require_admin
|
2020-02-25 19:18:21 +00:00
|
|
|
@websocket_api.async_response
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
"type": "lovelace/config/delete",
|
|
|
|
vol.Optional(CONF_URL_PATH): vol.Any(None, cv.string),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@_handle_errors
|
|
|
|
async def websocket_lovelace_delete_config(hass, connection, msg, config):
|
|
|
|
"""Delete Lovelace UI configuration."""
|
|
|
|
await config.async_delete()
|
2020-02-28 20:43:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.websocket_command({"type": "lovelace/dashboards/list"})
|
|
|
|
@callback
|
|
|
|
def websocket_lovelace_dashboards(hass, connection, msg):
|
|
|
|
"""Delete Lovelace UI configuration."""
|
|
|
|
connection.send_result(
|
|
|
|
msg["id"],
|
|
|
|
[
|
|
|
|
dashboard.config
|
|
|
|
for dashboard in hass.data[DOMAIN]["dashboards"].values()
|
|
|
|
if dashboard.config
|
|
|
|
],
|
|
|
|
)
|