diff --git a/homeassistant/components/lovelace/__init__.py b/homeassistant/components/lovelace/__init__.py index e81af9e0d27..ec131c8a4d9 100644 --- a/homeassistant/components/lovelace/__init__.py +++ b/homeassistant/components/lovelace/__init__.py @@ -24,6 +24,7 @@ FORMAT_JSON = 'json' 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_GET_CARD = 'lovelace/config/card/get' WS_TYPE_UPDATE_CARD = 'lovelace/config/card/update' WS_TYPE_ADD_CARD = 'lovelace/config/card/add' @@ -35,6 +36,10 @@ SCHEMA_GET_LOVELACE_UI = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ OLD_WS_TYPE_GET_LOVELACE_UI), }) +SCHEMA_MIGRATE_CONFIG = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ + vol.Required('type'): WS_TYPE_MIGRATE_CONFIG, +}) + SCHEMA_GET_CARD = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ vol.Required('type'): WS_TYPE_GET_CARD, vol.Required('card_id'): str, @@ -150,6 +155,11 @@ def load_yaml(fname: str) -> JSON_TYPE: def load_config(fname: str) -> JSON_TYPE: + """Load a YAML file.""" + return load_yaml(fname) + + +def migrate_config(fname: str) -> JSON_TYPE: """Load a YAML file and adds id to views and cards if not present.""" config = load_yaml(fname) # Check if all views and cards have a unique id or else add one @@ -341,6 +351,10 @@ 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_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) @@ -392,6 +406,30 @@ async def websocket_lovelace_config(hass, connection, msg): connection.send_message(message) +@websocket_api.async_response +async def websocket_lovelace_migrate_config(hass, connection, msg): + """Migrate lovelace UI config.""" + error = None + try: + config = await hass.async_add_executor_job( + migrate_config, hass.config.path(LOVELACE_CONFIG_FILE)) + message = websocket_api.result_message( + msg['id'], config + ) + except FileNotFoundError: + error = ('file_not_found', + 'Could not find ui-lovelace.yaml in your config dir.') + except UnsupportedYamlError as err: + error = 'unsupported_error', str(err) + except HomeAssistantError as err: + error = 'load_error', str(err) + + if error is not None: + message = websocket_api.error_message(msg['id'], *error) + + connection.send_message(message) + + @websocket_api.async_response async def websocket_lovelace_get_card(hass, connection, msg): """Send lovelace card config over websocket config.""" diff --git a/tests/components/lovelace/test_init.py b/tests/components/lovelace/test_init.py index 21362a32193..212bd9e2722 100644 --- a/tests/components/lovelace/test_init.py +++ b/tests/components/lovelace/test_init.py @@ -9,8 +9,8 @@ from ruamel.yaml import YAML from homeassistant.exceptions import HomeAssistantError from homeassistant.setup import async_setup_component from homeassistant.components.websocket_api.const import TYPE_RESULT -from homeassistant.components.lovelace import (load_yaml, - save_yaml, load_config, +from homeassistant.components.lovelace import (load_yaml, migrate_config, + save_yaml, UnsupportedYamlError) TEST_YAML_A = """\ @@ -164,7 +164,7 @@ class TestYAML(unittest.TestCase): with patch('homeassistant.components.lovelace.load_yaml', return_value=self.yaml.load(TEST_YAML_A)), \ patch('homeassistant.components.lovelace.save_yaml'): - data = load_config(fname) + data = migrate_config(fname) assert 'id' in data['views'][0]['cards'][0] assert 'id' in data['views'][1] @@ -173,7 +173,7 @@ class TestYAML(unittest.TestCase): fname = self._path_for("test7") with patch('homeassistant.components.lovelace.load_yaml', return_value=self.yaml.load(TEST_YAML_B)): - data = load_config(fname) + data = migrate_config(fname) assert data == self.yaml.load(TEST_YAML_B)