Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions homeassistant/components/lovelace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
OLD_WS_TYPE_GET_LOVELACE_UI = 'frontend/lovelace_config'
WS_TYPE_GET_LOVELACE_UI = 'lovelace/config'
WS_TYPE_MIGRATE_CONFIG = 'lovelace/config/migrate'
WS_TYPE_SAVE_CONFIG = 'lovelace/config/save'

WS_TYPE_GET_CARD = 'lovelace/config/card/get'
WS_TYPE_UPDATE_CARD = 'lovelace/config/card/update'
Expand All @@ -53,6 +54,13 @@
vol.Required('type'): WS_TYPE_MIGRATE_CONFIG,
})

SCHEMA_SAVE_CONFIG = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
vol.Required('type'): WS_TYPE_SAVE_CONFIG,
vol.Required('config'): vol.Any(str, Dict),
vol.Optional('format', default=FORMAT_JSON):
vol.Any(FORMAT_JSON, FORMAT_YAML),
})

SCHEMA_GET_CARD = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
vol.Required('type'): WS_TYPE_GET_CARD,
vol.Required('card_id'): str,
Expand Down Expand Up @@ -204,6 +212,13 @@ def migrate_config(fname: str) -> None:
yaml.save_yaml(fname, config)


def save_config(fname: str, config, data_format: str = FORMAT_JSON) -> None:
"""Save config to file."""
if data_format == FORMAT_YAML:
config = yaml.yaml_to_object(config)
yaml.save_yaml(fname, config)


def get_card(fname: str, card_id: str, data_format: str = FORMAT_YAML)\
-> JSON_TYPE:
"""Load a specific card config for id."""
Expand Down Expand Up @@ -422,13 +437,17 @@ async def async_setup(hass, config):
OLD_WS_TYPE_GET_LOVELACE_UI, websocket_lovelace_config,
SCHEMA_GET_LOVELACE_UI)

hass.components.websocket_api.async_register_command(
WS_TYPE_GET_LOVELACE_UI, websocket_lovelace_config,
SCHEMA_GET_LOVELACE_UI)

hass.components.websocket_api.async_register_command(
WS_TYPE_MIGRATE_CONFIG, websocket_lovelace_migrate_config,
SCHEMA_MIGRATE_CONFIG)

hass.components.websocket_api.async_register_command(
WS_TYPE_GET_LOVELACE_UI, websocket_lovelace_config,
SCHEMA_GET_LOVELACE_UI)
WS_TYPE_SAVE_CONFIG, websocket_lovelace_save_config,
SCHEMA_SAVE_CONFIG)

hass.components.websocket_api.async_register_command(
WS_TYPE_GET_CARD, websocket_lovelace_get_card, SCHEMA_GET_CARD)
Expand Down Expand Up @@ -516,6 +535,15 @@ async def websocket_lovelace_migrate_config(hass, connection, msg):
migrate_config, hass.config.path(LOVELACE_CONFIG_FILE))


@websocket_api.async_response
@handle_yaml_errors
async def websocket_lovelace_save_config(hass, connection, msg):
"""Save Lovelace UI configuration."""
return await hass.async_add_executor_job(
save_config, hass.config.path(LOVELACE_CONFIG_FILE), msg['config'],
msg.get('format', FORMAT_JSON))


@websocket_api.async_response
@handle_yaml_errors
async def websocket_lovelace_get_card(hass, connection, msg):
Expand Down
10 changes: 7 additions & 3 deletions homeassistant/util/ruamel_yaml.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""ruamel.yaml utility functions."""
import logging
import os
from os import O_CREAT, O_TRUNC, O_WRONLY
from os import O_CREAT, O_TRUNC, O_WRONLY, stat_result
from collections import OrderedDict
from typing import Union, List, Dict

Expand Down Expand Up @@ -104,13 +104,17 @@ def save_yaml(fname: str, data: JSON_TYPE) -> None:
yaml.indent(sequence=4, offset=2)
tmp_fname = fname + "__TEMP__"
try:
file_stat = os.stat(fname)
try:
file_stat = os.stat(fname)
except OSError:
file_stat = stat_result(
(0o644, -1, -1, -1, -1, -1, -1, -1, -1, -1))
with open(os.open(tmp_fname, O_WRONLY | O_CREAT | O_TRUNC,
file_stat.st_mode), 'w', encoding='utf-8') \
as temp_file:
yaml.dump(data, temp_file)
os.replace(tmp_fname, fname)
if hasattr(os, 'chown'):
if hasattr(os, 'chown') and file_stat.st_ctime > -1:
try:
os.chown(fname, file_stat.st_uid, file_stat.st_gid)
except OSError:
Expand Down