diff --git a/API.md b/API.md index bb38ffe0f..1951dc0f6 100644 --- a/API.md +++ b/API.md @@ -269,7 +269,9 @@ Optional: { "version": "INSTALL_VERSION", "last_version": "LAST_VERSION", - "devices": [] + "devices": [""], + "image": "str", + "custom": "bool -> if custom image" } ``` @@ -291,9 +293,13 @@ Output the raw docker log ```json { "devices": [], + "image": "Optional|null", + "last_version": "Optional for custom image|null" } ``` +Image with `null` and last_version with `null` reset this options. + ### REST API addons - POST `/addons/reload` diff --git a/hassio/addons/data.py b/hassio/addons/data.py index 35c1cddce..7d8e00e79 100644 --- a/hassio/addons/data.py +++ b/hassio/addons/data.py @@ -15,53 +15,22 @@ from .validate import ( from ..const import ( FILE_HASSIO_ADDONS, ATTR_VERSION, ATTR_SLUG, ATTR_REPOSITORY, ATTR_LOCATON, REPOSITORY_CORE, REPOSITORY_LOCAL, ATTR_USER, ATTR_SYSTEM) -from ..tools import read_json_file, write_json_file +from ..tools import JsonConfig, read_json_file _LOGGER = logging.getLogger(__name__) RE_VOLUME = re.compile(MAP_VOLUME) -class Data(object): +class Data(JsonConfig): """Hold data for addons inside HassIO.""" def __init__(self, config): """Initialize data holder.""" - self._file = FILE_HASSIO_ADDONS - self._data = {} + super().__init__(FILE_HASSIO_ADDONS, SCHEMA_ADDON_FILE) self.config = config - self._cache = {} self._repositories = {} - - # init or load data - if self._file.is_file(): - try: - self._data = read_json_file(self._file) - except (OSError, json.JSONDecodeError): - _LOGGER.warning("Can't read %s", self._file) - self._data = {} - - # validate - try: - self._data = SCHEMA_ADDON_FILE(self._data) - except vol.Invalid as ex: - _LOGGER.error("Can't parse addons.json -> %s", - humanize_error(self._data, ex)) - - def save(self): - """Store data to config file.""" - # validate - try: - self._data = SCHEMA_ADDON_FILE(self._data) - except vol.Invalid as ex: - _LOGGER.error("Can't parse addons data -> %s", - humanize_error(self._data, ex)) - return False - - if not write_json_file(self._file, self._data): - _LOGGER.error("Can't store config in %s", self._file) - return False - return True + self._cache = {} @property def user(self): diff --git a/hassio/api/homeassistant.py b/hassio/api/homeassistant.py index 6ba15511a..9b10497ca 100644 --- a/hassio/api/homeassistant.py +++ b/hassio/api/homeassistant.py @@ -5,7 +5,8 @@ import logging import voluptuous as vol from .util import api_process, api_process_raw, api_validate -from ..const import ATTR_VERSION, ATTR_LAST_VERSION, ATTR_DEVICES +from ..const import ( + ATTR_VERSION, ATTR_LAST_VERSION, ATTR_DEVICES, ATTR_IMAGE, ATTR_CUSTOM) from ..validate import HASS_DEVICES _LOGGER = logging.getLogger(__name__) @@ -13,6 +14,9 @@ _LOGGER = logging.getLogger(__name__) SCHEMA_OPTIONS = vol.Schema({ vol.Optional(ATTR_DEVICES): HASS_DEVICES, + vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Any(None, vol.Coerce(str)), + vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'): + vol.Any(None, vol.Coerce(str)), }) SCHEMA_VERSION = vol.Schema({ @@ -34,8 +38,10 @@ class APIHomeAssistant(object): """Return host information.""" return { ATTR_VERSION: self.homeassistant.version, - ATTR_LAST_VERSION: self.config.last_homeassistant, - ATTR_DEVICES: self.config.homeassistant_devices, + ATTR_LAST_VERSION: self.homeassistant.last_version, + ATTR_IMAGE: self.homeassistant.image, + ATTR_DEVICES: self.homeassistant.devices, + ATTR_CUSTOM: self.homeassistant.is_custom_image, } @api_process @@ -44,7 +50,11 @@ class APIHomeAssistant(object): body = await api_validate(SCHEMA_OPTIONS, request) if ATTR_DEVICES in body: - self.config.homeassistant_devices = body[ATTR_DEVICES] + self.homeassistant.devices = body[ATTR_DEVICES] + + if ATTR_IMAGE in body: + self.homeassistant.set_custom( + body[ATTR_IMAGE], body[ATTR_LAST_VERSION]) return True @@ -57,9 +67,6 @@ class APIHomeAssistant(object): if self.homeassistant.in_progress: raise RuntimeError("Other task is in progress") - if version == self.homeassistant.version: - raise RuntimeError("Version is already in use") - return await asyncio.shield( self.homeassistant.update(version), loop=self.loop) diff --git a/hassio/config.py b/hassio/config.py index 02fe0e3a4..b8a2630fb 100644 --- a/hassio/config.py +++ b/hassio/config.py @@ -1,17 +1,13 @@ """Bootstrap HassIO.""" from datetime import datetime import logging -import json import os from pathlib import Path, PurePath import voluptuous as vol -from voluptuous.humanize import humanize_error from .const import FILE_HASSIO_CONFIG, HASSIO_DATA -from .tools import ( - fetch_last_versions, write_json_file, read_json_file, validate_timezone) -from .validate import HASS_DEVICES +from .tools import fetch_last_versions, JsonConfig, validate_timezone _LOGGER = logging.getLogger(__name__) @@ -19,7 +15,6 @@ DATETIME_FORMAT = "%Y%m%d %H:%M:%S" HOMEASSISTANT_CONFIG = PurePath("homeassistant") HOMEASSISTANT_LAST = 'homeassistant_last' -HOMEASSISTANT_DEVICES = 'homeassistant_devices' HASSIO_SSL = PurePath("ssl") HASSIO_LAST = 'hassio_last' @@ -50,7 +45,6 @@ SCHEMA_CONFIG = vol.Schema({ vol.Optional(API_ENDPOINT): vol.Coerce(str), vol.Optional(TIMEZONE, default='UTC'): validate_timezone, vol.Optional(HOMEASSISTANT_LAST): vol.Coerce(str), - vol.Optional(HOMEASSISTANT_DEVICES, default=[]): HASS_DEVICES, vol.Optional(HASSIO_LAST): vol.Coerce(str), vol.Optional(ADDONS_CUSTOM_LIST, default=[]): [vol.Url()], vol.Optional(SECURITY_INITIALIZE, default=False): vol.Boolean(), @@ -61,48 +55,13 @@ SCHEMA_CONFIG = vol.Schema({ }, extra=vol.REMOVE_EXTRA) -class CoreConfig(object): +class CoreConfig(JsonConfig): """Hold all core config data.""" def __init__(self): """Initialize config object.""" + super().__init__(FILE_HASSIO_CONFIG, SCHEMA_CONFIG) self.arch = None - self._file = FILE_HASSIO_CONFIG - self._data = {} - - # init or load data - if self._file.is_file(): - try: - self._data = read_json_file(self._file) - except (OSError, json.JSONDecodeError): - _LOGGER.warning("Can't read %s", self._file) - self._data = {} - - # validate data - if not self._validate_config(): - self._data = SCHEMA_CONFIG({}) - - def _validate_config(self): - """Validate config and return True or False.""" - # validate data - try: - self._data = SCHEMA_CONFIG(self._data) - except vol.Invalid as ex: - _LOGGER.warning( - "Invalid config %s", humanize_error(self._data, ex)) - return False - - return True - - def save(self): - """Store data to config file.""" - if not self._validate_config(): - return False - - if not write_json_file(self._file, self._data): - _LOGGER.error("Can't store config in %s", self._file) - return False - return True async def fetch_update_infos(self, websession): """Read current versions from web.""" @@ -150,22 +109,6 @@ class CoreConfig(object): self._data[TIMEZONE] = value self.save() - @property - def homeassistant_devices(self): - """Return list of special device to map into homeassistant.""" - return self._data[HOMEASSISTANT_DEVICES] - - @homeassistant_devices.setter - def homeassistant_devices(self, value): - """Set list of special device.""" - self._data[HOMEASSISTANT_DEVICES] = value - self.save() - - @property - def homeassistant_image(self): - """Return docker homeassistant repository.""" - return os.environ['HOMEASSISTANT_REPOSITORY'] - @property def last_homeassistant(self): """Actual version of homeassistant.""" diff --git a/hassio/const.py b/hassio/const.py index f63515f14..88ca1be6b 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -24,6 +24,7 @@ RESTART_EXIT_CODE = 100 FILE_HASSIO_ADDONS = Path(HASSIO_DATA, "addons.json") FILE_HASSIO_CONFIG = Path(HASSIO_DATA, "config.json") +FILE_HASSIO_HOMEASSISTANT = Path(HASSIO_DATA, "homeassistant.json") SOCKET_DOCKER = Path("/var/run/docker.sock") SOCKET_HC = Path("/var/run/hassio-hc.sock") @@ -94,6 +95,7 @@ ATTR_SIZE = 'size' ATTR_TYPE = 'type' ATTR_TIMEOUT = 'timeout' ATTR_AUTO_UPDATE = 'auto_update' +ATTR_CUSTOM = 'custom' STARTUP_INITIALIZE = 'initialize' STARTUP_BEFORE = 'before' diff --git a/hassio/core.py b/hassio/core.py index eaba036e9..0544b7d76 100644 --- a/hassio/core.py +++ b/hassio/core.py @@ -13,13 +13,12 @@ from .const import ( RUN_UPDATE_SUPERVISOR_TASKS, RUN_WATCHDOG_HOMEASSISTANT, RUN_CLEANUP_API_SESSIONS, STARTUP_AFTER, STARTUP_BEFORE, STARTUP_INITIALIZE, RUN_RELOAD_SNAPSHOTS_TASKS, RUN_UPDATE_ADDONS_TASKS) +from .homeassistant import HomeAssistant from .scheduler import Scheduler -from .dock.homeassistant import DockerHomeAssistant from .dock.supervisor import DockerSupervisor from .snapshots import SnapshotsManager from .tasks import ( - hassio_update, homeassistant_watchdog, homeassistant_setup, - api_sessions_cleanup, addons_update) + hassio_update, homeassistant_watchdog, api_sessions_cleanup, addons_update) from .tools import get_local_ip, fetch_timezone _LOGGER = logging.getLogger(__name__) @@ -41,7 +40,10 @@ class HassIO(object): # init basic docker container self.supervisor = DockerSupervisor(config, loop, self.dock, self.stop) - self.homeassistant = DockerHomeAssistant(config, loop, self.dock) + + # init homeassistant + self.homeassistant = HomeAssistant( + config, loop, self.dock, self.websession) # init HostControl self.host_control = HostControl(loop) @@ -94,13 +96,8 @@ class HassIO(object): api_sessions_cleanup(self.config), RUN_CLEANUP_API_SESSIONS, now=True) - # first start of supervisor? - if not await self.homeassistant.exists(): - _LOGGER.info("No HomeAssistant docker found.") - await homeassistant_setup( - self.config, self.loop, self.homeassistant, self.websession) - else: - await self.homeassistant.attach() + # Load homeassistant + await self.homeassistant.prepare() # Load addons await self.addons.prepare() @@ -157,6 +154,10 @@ class HassIO(object): homeassistant_watchdog(self.loop, self.homeassistant), RUN_WATCHDOG_HOMEASSISTANT) + # If landingpage / run upgrade in background + if self.homeassistant.version == 'landingpage': + self.loop.create_task(self.homeassistant.install()) + async def stop(self, exit_code=0): """Stop a running orchestration.""" # don't process scheduler anymore diff --git a/hassio/dock/__init__.py b/hassio/dock/__init__.py index 733bbce67..7fb7adb4d 100644 --- a/hassio/dock/__init__.py +++ b/hassio/dock/__init__.py @@ -260,9 +260,13 @@ class DockerBase(object): if not self._install(tag): return False - # cleanup old stuff + # run or cleanup container if was_running: self._run() + else: + self._stop() + + # cleanup images self._cleanup() return True diff --git a/hassio/dock/homeassistant.py b/hassio/dock/homeassistant.py index 7b361bf5b..d86202b66 100644 --- a/hassio/dock/homeassistant.py +++ b/hassio/dock/homeassistant.py @@ -13,9 +13,10 @@ HASS_DOCKER_NAME = 'homeassistant' class DockerHomeAssistant(DockerBase): """Docker hassio wrapper for HomeAssistant.""" - def __init__(self, config, loop, dock): + def __init__(self, config, loop, dock, data): """Initialize docker homeassistant wrapper.""" - super().__init__(config, loop, dock, image=config.homeassistant_image) + super().__init__(config, loop, dock, image=data.image) + self.data = data @property def name(self): @@ -25,11 +26,11 @@ class DockerHomeAssistant(DockerBase): @property def devices(self): """Create list of special device to map into docker.""" - if not self.config.homeassistant_devices: + if not self.data.devices: return devices = [] - for device in self.config.homeassistant_devices: + for device in self.data.devices: devices.append("/dev/{0}:/dev/{0}:rwm".format(device)) return devices diff --git a/hassio/homeassistant.py b/hassio/homeassistant.py new file mode 100644 index 000000000..70bcf05c6 --- /dev/null +++ b/hassio/homeassistant.py @@ -0,0 +1,162 @@ +"""HomeAssistant control object.""" +import asyncio +import logging +import os + +from .const import ( + FILE_HASSIO_HOMEASSISTANT, ATTR_DEVICES, ATTR_IMAGE, ATTR_LAST_VERSION, + ATTR_VERSION) +from .dock.homeassistant import DockerHomeAssistant +from .tools import JsonConfig +from .validate import SCHEMA_HASS_CONFIG + +_LOGGER = logging.getLogger(__name__) + + +class HomeAssistant(JsonConfig): + """Hass core object for handle it.""" + + def __init__(self, config, loop, dock, websession): + """Initialize hass object.""" + super().__init__(FILE_HASSIO_HOMEASSISTANT, SCHEMA_HASS_CONFIG) + self.config = config + self.loop = loop + self.websession = websession + self.docker = DockerHomeAssistant(config, loop, dock, self) + + async def prepare(self): + """Prepare HomeAssistant object.""" + if not await self.docker.exists(): + _LOGGER.info("No HomeAssistant docker %s found.", self.image) + if self.is_custom_image: + await self.install() + else: + await self.install_landingpage() + else: + await self.docker.attach() + + @property + def version(self): + """Return version of running homeassistant.""" + return self.docker.version + + @property + def last_version(self): + """Return last available version of homeassistant.""" + if self.is_custom_image: + return self._data.get(ATTR_LAST_VERSION) + return self.config.last_homeassistant + + @property + def image(self): + """Return image name of hass containter.""" + if ATTR_IMAGE in self._data: + return self._data[ATTR_IMAGE] + return os.environ['HOMEASSISTANT_REPOSITORY'] + + @property + def is_custom_image(self): + """Return True if a custom image is used.""" + return ATTR_IMAGE in self._data + + @property + def devices(self): + """Return extend device mapping.""" + return self._data[ATTR_DEVICES] + + @devices.setter + def devices(self, value): + """Set extend device mapping.""" + self._data[ATTR_DEVICES] = value + self.save() + + def set_custom(self, image, version): + """Set a custom image for homeassistant.""" + # reset + if image is None and version is None: + self._data.pop(ATTR_IMAGE, None) + self._data.pop(ATTR_VERSION, None) + + self.docker.image = self.image + else: + if image: + self._data[ATTR_IMAGE] = image + self.docker.image = image + if version: + self._data[ATTR_VERSION] = version + self.save() + + async def install_landingpage(self): + """Install a landingpage.""" + _LOGGER.info("Setup HomeAssistant landingpage") + while True: + if await self.docker.install('landingpage'): + break + _LOGGER.warning("Fails install landingpage, retry after 60sec") + await asyncio.sleep(60, loop=self.loop) + + async def install(self): + """Install a landingpage.""" + _LOGGER.info("Setup HomeAssistant") + while True: + # read homeassistant tag and install it + if not self.last_version: + await self.config.fetch_update_infos(self.websession) + + tag = self.last_version + if tag and await self.docker.install(tag): + break + _LOGGER.warning("Error on install HomeAssistant. Retry in 60sec") + await asyncio.sleep(60, loop=self.loop) + + # store version + _LOGGER.info("HomeAssistant docker now installed") + await self.docker.cleanup() + + def update(self, version=None): + """Update HomeAssistant version. + + Return a coroutine. + """ + version = version or self.last_version + return self.docker.update(version) + + def run(self): + """Run HomeAssistant docker. + + Return a coroutine. + """ + return self.docker.run() + + def stop(self): + """Stop HomeAssistant docker. + + Return a coroutine. + """ + return self.docker.stop() + + def restart(self): + """Restart HomeAssistant docker. + + Return a coroutine. + """ + return self.docker.restart() + + def logs(self): + """Get HomeAssistant docker logs. + + Return a coroutine. + """ + return self.docker.logs() + + def is_running(self): + """Return True if docker container is running. + + Return a coroutine. + """ + return self.docker.is_running() + + @property + def in_progress(self): + """Return True if a task is in progress.""" + return self.docker.in_progress diff --git a/hassio/snapshots/__init__.py b/hassio/snapshots/__init__.py index 29f3b277a..bc8603a9b 100644 --- a/hassio/snapshots/__init__.py +++ b/hassio/snapshots/__init__.py @@ -46,8 +46,7 @@ class SnapshotsManager(object): snapshot.create(slug, name, date_str, sys_type) # set general data - snapshot.homeassistant_version = self.homeassistant.version - snapshot.homeassistant_devices = self.config.homeassistant_devices + snapshot.snapshot_homeassistant(self.homeassistant) snapshot.repositories = self.config.addons_repositories return snapshot @@ -198,8 +197,7 @@ class SnapshotsManager(object): await snapshot.restore_folders() # start homeassistant restore - self.config.homeassistant_devices = \ - snapshot.homeassistant_devices + snapshot.restore_homeassistant(self.homeassistant) task_hass = self.loop.create_task( self.homeassistant.update(snapshot.homeassistant_version)) @@ -281,8 +279,7 @@ class SnapshotsManager(object): await snapshot.restore_folders(folders) if homeassistant: - self.config.homeassistant_devices = \ - snapshot.homeassistant_devices + snapshot.restore_homeassistant(self.homeassistant) tasks.append(self.homeassistant.update( snapshot.homeassistant_version)) diff --git a/hassio/snapshots/snapshot.py b/hassio/snapshots/snapshot.py index 1882a5f07..41a03a8f3 100644 --- a/hassio/snapshots/snapshot.py +++ b/hassio/snapshots/snapshot.py @@ -13,7 +13,8 @@ from .validate import SCHEMA_SNAPSHOT, ALL_FOLDERS from .util import remove_folder from ..const import ( ATTR_SLUG, ATTR_NAME, ATTR_DATE, ATTR_ADDONS, ATTR_REPOSITORIES, - ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_DEVICES) + ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_DEVICES, + ATTR_IMAGE) from ..tools import write_json_file _LOGGER = logging.getLogger(__name__) @@ -90,6 +91,16 @@ class Snapshot(object): """Set snapshot homeassistant devices.""" self._data[ATTR_HOMEASSISTANT][ATTR_DEVICES] = value + @property + def homeassistant_image(self): + """Return snapshot homeassistant custom image.""" + return self._data[ATTR_HOMEASSISTANT].get(ATTR_IMAGE) + + @homeassistant_image.setter + def homeassistant_image(self, value): + """Set snapshot homeassistant custom image.""" + self._data[ATTR_HOMEASSISTANT][ATTR_IMAGE] = value + @property def size(self): """Return snapshot size.""" @@ -111,6 +122,24 @@ class Snapshot(object): self._data[ATTR_REPOSITORIES] = [] self._data[ATTR_FOLDERS] = [] + def snapshot_homeassistant(self, homeassistant): + """Read all data from homeassistant object.""" + self.homeassistant_version = homeassistant.version + self.homeassistant_devices = homeassistant.devices + + # custom image + if homeassistant.is_custom_image: + self.homeassistant_image = homeassistant.image + + def restore_homeassistant(self, homeassistant): + """Write all data to homeassistant object.""" + homeassistant.devices = self.homeassistant_devices + + # custom image + if self.homeassistant_image: + homeassistant.set_custom( + self.homeassistant_image, self.homeassistant_version) + async def load(self): """Read snapshot.json from tar file.""" if not self.tar_file.is_file(): diff --git a/hassio/snapshots/validate.py b/hassio/snapshots/validate.py index 2259009d5..e0a497d76 100644 --- a/hassio/snapshots/validate.py +++ b/hassio/snapshots/validate.py @@ -5,7 +5,7 @@ import voluptuous as vol from ..const import ( ATTR_REPOSITORIES, ATTR_ADDONS, ATTR_NAME, ATTR_SLUG, ATTR_DATE, ATTR_VERSION, ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_TYPE, ATTR_DEVICES, - FOLDER_SHARE, FOLDER_HOMEASSISTANT, FOLDER_ADDONS, FOLDER_SSL, + ATTR_IMAGE, FOLDER_SHARE, FOLDER_HOMEASSISTANT, FOLDER_ADDONS, FOLDER_SSL, SNAPSHOT_FULL, SNAPSHOT_PARTIAL) from ..validate import HASS_DEVICES @@ -20,6 +20,7 @@ SCHEMA_SNAPSHOT = vol.Schema({ vol.Required(ATTR_HOMEASSISTANT): vol.Schema({ vol.Required(ATTR_VERSION): vol.Coerce(str), vol.Optional(ATTR_DEVICES, default=[]): HASS_DEVICES, + vol.Optional(ATTR_IMAGE): vol.Coerce(str), }), vol.Optional(ATTR_FOLDERS, default=[]): [vol.In(ALL_FOLDERS)], vol.Optional(ATTR_ADDONS, default=[]): [vol.Schema({ diff --git a/hassio/tasks.py b/hassio/tasks.py index 25409e16e..a3421b560 100644 --- a/hassio/tasks.py +++ b/hassio/tasks.py @@ -66,20 +66,3 @@ def homeassistant_watchdog(loop, homeassistant): loop.create_task(homeassistant.run()) return _homeassistant_watchdog - - -async def homeassistant_setup(config, loop, homeassistant, websession): - """Install a homeassistant docker container.""" - while True: - # read homeassistant tag and install it - if not config.last_homeassistant: - await config.fetch_update_infos(websession) - - tag = config.last_homeassistant - if tag and await homeassistant.install(tag): - break - _LOGGER.warning("Error on setup HomeAssistant. Retry in 60.") - await asyncio.sleep(60, loop=loop) - - # store version - _LOGGER.info("HomeAssistant docker now installed.") diff --git a/hassio/tools.py b/hassio/tools.py index 7147fe62d..975cfc303 100644 --- a/hassio/tools.py +++ b/hassio/tools.py @@ -9,6 +9,7 @@ import aiohttp import async_timeout import pytz import voluptuous as vol +from voluptuous.humanize import humanize_error from .const import URL_HASSIO_VERSION, URL_HASSIO_VERSION_BETA @@ -98,3 +99,44 @@ async def fetch_timezone(websession): data = await request.json() return data.get('time_zone', 'UTC') + + +class JsonConfig(object): + """Hass core object for handle it.""" + + def __init__(self, json_file, schema): + """Initialize hass object.""" + self._file = json_file + self._schema = schema + self._data = {} + + # init or load data + if self._file.is_file(): + try: + self._data = read_json_file(self._file) + except (OSError, json.JSONDecodeError): + _LOGGER.warning("Can't read %s", self._file) + self._data = {} + + # validate + try: + self._data = self._schema(self._data) + except vol.Invalid as ex: + _LOGGER.error("Can't parse %s -> %s", + self._file, humanize_error(self._data, ex)) + + def save(self): + """Store data to config file.""" + # validate + try: + self._data = self._schema(self._data) + except vol.Invalid as ex: + _LOGGER.error("Can't parse data -> %s", + humanize_error(self._data, ex)) + return False + + # write + if not write_json_file(self._file, self._data): + _LOGGER.error("Can't store config in %s", self._file) + return False + return True diff --git a/hassio/validate.py b/hassio/validate.py index 4a97a54b7..ae0cb5a60 100644 --- a/hassio/validate.py +++ b/hassio/validate.py @@ -1,6 +1,9 @@ """Validate functions.""" import voluptuous as vol +from .const import ATTR_DEVICES, ATTR_IMAGE, ATTR_LAST_VERSION + + NETWORK_PORT = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)) HASS_DEVICES = [vol.Match(r"^[^/]*$")] @@ -30,3 +33,10 @@ DOCKER_PORTS = vol.Schema({ vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): convert_to_docker_ports, }) + + +SCHEMA_HASS_CONFIG = vol.Schema({ + vol.Optional(ATTR_DEVICES, default=[]): HASS_DEVICES, + vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Coerce(str), + vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'): vol.Coerce(str), +})