2016-02-20 07:20:14 +00:00
|
|
|
"""Provides methods to bootstrap a home assistant instance."""
|
2013-10-13 17:42:22 +00:00
|
|
|
|
2013-10-22 05:06:22 +00:00
|
|
|
import logging
|
2015-09-04 22:22:42 +00:00
|
|
|
import logging.handlers
|
2015-11-15 10:05:46 +00:00
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import sys
|
2016-02-19 05:27:50 +00:00
|
|
|
from collections import defaultdict
|
2016-02-20 07:20:14 +00:00
|
|
|
from threading import RLock
|
2013-10-13 17:42:22 +00:00
|
|
|
|
2016-03-28 01:48:51 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2016-02-19 05:27:50 +00:00
|
|
|
import homeassistant.components as core_components
|
|
|
|
import homeassistant.components.group as group
|
|
|
|
import homeassistant.config as config_util
|
2015-08-17 03:44:46 +00:00
|
|
|
import homeassistant.core as core
|
2016-05-07 14:35:42 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2016-02-19 05:27:50 +00:00
|
|
|
import homeassistant.loader as loader
|
2015-04-29 02:12:05 +00:00
|
|
|
import homeassistant.util.dt as date_util
|
2015-07-07 07:00:21 +00:00
|
|
|
import homeassistant.util.location as loc_util
|
2016-02-19 05:27:50 +00:00
|
|
|
import homeassistant.util.package as pkg_util
|
|
|
|
from homeassistant.const import (
|
|
|
|
CONF_CUSTOMIZE, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME,
|
|
|
|
CONF_TEMPERATURE_UNIT, CONF_TIME_ZONE, EVENT_COMPONENT_LOADED,
|
2016-04-20 03:30:44 +00:00
|
|
|
TEMP_CELSIUS, TEMP_FAHRENHEIT, PLATFORM_FORMAT, __version__)
|
2016-04-09 22:25:01 +00:00
|
|
|
from homeassistant.exceptions import HomeAssistantError
|
2016-03-28 01:48:51 +00:00
|
|
|
from homeassistant.helpers import (
|
2016-06-22 16:13:18 +00:00
|
|
|
event_decorators, service, config_per_platform, extract_domain_configs,
|
|
|
|
entity)
|
2014-01-24 05:34:08 +00:00
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2016-02-20 07:20:14 +00:00
|
|
|
_SETUP_LOCK = RLock()
|
|
|
|
_CURRENT_SETUP = []
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2015-05-12 05:23:38 +00:00
|
|
|
ATTR_COMPONENT = 'component'
|
2015-02-14 06:49:56 +00:00
|
|
|
|
2015-11-07 09:44:02 +00:00
|
|
|
ERROR_LOG_FILENAME = 'home-assistant.log'
|
2015-05-12 05:23:20 +00:00
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
|
|
|
|
def setup_component(hass, domain, config=None):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Setup a component and all its dependencies."""
|
2015-03-22 04:10:46 +00:00
|
|
|
if domain in hass.config.components:
|
2015-03-22 05:02:47 +00:00
|
|
|
return True
|
2015-01-30 07:56:04 +00:00
|
|
|
|
|
|
|
_ensure_loader_prepared(hass)
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
if config is None:
|
|
|
|
config = defaultdict(dict)
|
|
|
|
|
2015-03-22 05:02:47 +00:00
|
|
|
components = loader.load_order_component(domain)
|
|
|
|
|
|
|
|
# OrderedSet is empty if component or dependencies could not be resolved
|
|
|
|
if not components:
|
|
|
|
return False
|
|
|
|
|
|
|
|
for component in components:
|
|
|
|
if not _setup_component(hass, component, config):
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2015-08-30 01:11:24 +00:00
|
|
|
def _handle_requirements(hass, component, name):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Install the requirements for a component."""
|
2015-09-04 21:50:57 +00:00
|
|
|
if hass.config.skip_pip or not hasattr(component, 'REQUIREMENTS'):
|
2015-08-04 20:21:09 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
for req in component.REQUIREMENTS:
|
2016-04-12 03:07:50 +00:00
|
|
|
if not pkg_util.install_package(req, target=hass.config.path('deps')):
|
2015-08-04 20:21:09 +00:00
|
|
|
_LOGGER.error('Not initializing %s because could not install '
|
|
|
|
'dependency %s', name, req)
|
|
|
|
return False
|
|
|
|
|
2015-07-07 07:00:21 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
2015-03-22 05:02:47 +00:00
|
|
|
def _setup_component(hass, domain, config):
|
2016-02-20 07:20:14 +00:00
|
|
|
"""Setup a component for Home Assistant."""
|
2016-03-28 01:48:51 +00:00
|
|
|
# pylint: disable=too-many-return-statements,too-many-branches
|
2015-08-30 22:07:37 +00:00
|
|
|
if domain in hass.config.components:
|
|
|
|
return True
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
with _SETUP_LOCK:
|
|
|
|
# It might have been loaded while waiting for lock
|
|
|
|
if domain in hass.config.components:
|
|
|
|
return True
|
2015-03-22 05:02:47 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
if domain in _CURRENT_SETUP:
|
|
|
|
_LOGGER.error('Attempt made to setup %s during setup of %s',
|
|
|
|
domain, domain)
|
|
|
|
return False
|
2015-03-22 05:02:47 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
component = loader.get_component(domain)
|
|
|
|
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
|
|
|
|
if dep not in hass.config.components]
|
2015-07-07 07:00:21 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
if missing_deps:
|
|
|
|
_LOGGER.error(
|
|
|
|
'Not initializing %s because not all dependencies loaded: %s',
|
|
|
|
domain, ", ".join(missing_deps))
|
2015-08-03 15:05:33 +00:00
|
|
|
return False
|
|
|
|
|
2016-03-28 01:48:51 +00:00
|
|
|
if hasattr(component, 'CONFIG_SCHEMA'):
|
|
|
|
try:
|
|
|
|
config = component.CONFIG_SCHEMA(config)
|
|
|
|
except vol.MultipleInvalid as ex:
|
2016-05-08 05:24:04 +00:00
|
|
|
cv.log_exception(_LOGGER, ex, domain, config)
|
2016-03-28 01:48:51 +00:00
|
|
|
return False
|
|
|
|
|
2016-03-30 05:51:33 +00:00
|
|
|
elif hasattr(component, 'PLATFORM_SCHEMA'):
|
2016-03-28 01:48:51 +00:00
|
|
|
platforms = []
|
2016-04-03 03:10:57 +00:00
|
|
|
for p_name, p_config in config_per_platform(config, domain):
|
|
|
|
# Validate component specific platform schema
|
2016-03-28 01:48:51 +00:00
|
|
|
try:
|
2016-04-03 03:10:57 +00:00
|
|
|
p_validated = component.PLATFORM_SCHEMA(p_config)
|
2016-03-28 01:48:51 +00:00
|
|
|
except vol.MultipleInvalid as ex:
|
2016-05-08 05:24:04 +00:00
|
|
|
cv.log_exception(_LOGGER, ex, domain, p_config)
|
2016-03-28 01:48:51 +00:00
|
|
|
return False
|
|
|
|
|
2016-04-04 19:18:58 +00:00
|
|
|
# Not all platform components follow same pattern for platforms
|
2016-05-08 05:24:04 +00:00
|
|
|
# So if p_name is None we are not going to validate platform
|
2016-04-04 19:18:58 +00:00
|
|
|
# (the automation component is one of them)
|
|
|
|
if p_name is None:
|
|
|
|
platforms.append(p_validated)
|
|
|
|
continue
|
|
|
|
|
2016-04-03 03:10:57 +00:00
|
|
|
platform = prepare_setup_platform(hass, config, domain,
|
|
|
|
p_name)
|
|
|
|
|
|
|
|
if platform is None:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Validate platform specific schema
|
|
|
|
if hasattr(platform, 'PLATFORM_SCHEMA'):
|
|
|
|
try:
|
|
|
|
p_validated = platform.PLATFORM_SCHEMA(p_validated)
|
|
|
|
except vol.MultipleInvalid as ex:
|
2016-05-07 14:35:42 +00:00
|
|
|
cv.log_exception(_LOGGER, ex, '{}.{}'
|
2016-05-08 05:24:04 +00:00
|
|
|
.format(domain, p_name), p_validated)
|
2016-04-03 03:10:57 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
platforms.append(p_validated)
|
|
|
|
|
2016-04-01 04:11:14 +00:00
|
|
|
# Create a copy of the configuration with all config for current
|
|
|
|
# component removed and add validated config back in.
|
|
|
|
filter_keys = extract_domain_configs(config, domain)
|
|
|
|
config = {key: value for key, value in config.items()
|
|
|
|
if key not in filter_keys}
|
|
|
|
config[domain] = platforms
|
2016-03-28 01:48:51 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
if not _handle_requirements(hass, component, domain):
|
|
|
|
return False
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
_CURRENT_SETUP.append(domain)
|
2015-08-03 15:05:33 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
try:
|
|
|
|
if not component.setup(hass, config):
|
|
|
|
_LOGGER.error('component %s failed to initialize', domain)
|
|
|
|
return False
|
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
_LOGGER.exception('Error during setup of component %s', domain)
|
|
|
|
return False
|
|
|
|
finally:
|
|
|
|
_CURRENT_SETUP.remove(domain)
|
2015-08-03 15:05:33 +00:00
|
|
|
|
2016-02-20 07:20:14 +00:00
|
|
|
hass.config.components.append(component.DOMAIN)
|
|
|
|
|
|
|
|
# Assumption: if a component does not depend on groups
|
|
|
|
# it communicates with devices
|
|
|
|
if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []):
|
|
|
|
hass.pool.add_worker()
|
|
|
|
|
|
|
|
hass.bus.fire(
|
|
|
|
EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN})
|
|
|
|
|
|
|
|
return True
|
2015-01-09 08:07:58 +00:00
|
|
|
|
|
|
|
|
2015-05-12 05:23:20 +00:00
|
|
|
def prepare_setup_platform(hass, config, domain, platform_name):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Load a platform and makes sure dependencies are setup."""
|
2015-05-12 05:23:20 +00:00
|
|
|
_ensure_loader_prepared(hass)
|
|
|
|
|
|
|
|
platform_path = PLATFORM_FORMAT.format(domain, platform_name)
|
|
|
|
|
2016-04-04 19:18:58 +00:00
|
|
|
platform = loader.get_platform(domain, platform_name)
|
2015-05-12 05:23:20 +00:00
|
|
|
|
|
|
|
# Not found
|
|
|
|
if platform is None:
|
2015-09-10 06:37:15 +00:00
|
|
|
_LOGGER.error('Unable to find platform %s', platform_path)
|
2015-05-12 05:23:20 +00:00
|
|
|
return None
|
|
|
|
|
2015-07-07 07:00:21 +00:00
|
|
|
# Already loaded
|
|
|
|
elif platform_path in hass.config.components:
|
2015-05-12 05:23:20 +00:00
|
|
|
return platform
|
|
|
|
|
|
|
|
# Load dependencies
|
2015-11-26 21:11:59 +00:00
|
|
|
for component in getattr(platform, 'DEPENDENCIES', []):
|
|
|
|
if not setup_component(hass, component, config):
|
|
|
|
_LOGGER.error(
|
|
|
|
'Unable to prepare setup for platform %s because '
|
|
|
|
'dependency %s could not be initialized', platform_path,
|
|
|
|
component)
|
|
|
|
return None
|
2015-07-07 07:00:21 +00:00
|
|
|
|
2015-08-30 01:11:24 +00:00
|
|
|
if not _handle_requirements(hass, platform, platform_path):
|
2015-07-07 07:00:21 +00:00
|
|
|
return None
|
2015-05-12 05:23:20 +00:00
|
|
|
|
|
|
|
return platform
|
|
|
|
|
|
|
|
|
2015-08-30 02:19:52 +00:00
|
|
|
def mount_local_lib_path(config_dir):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Add local library to Python Path."""
|
2016-04-12 03:07:50 +00:00
|
|
|
sys.path.insert(0, os.path.join(config_dir, 'deps'))
|
2015-08-30 02:19:52 +00:00
|
|
|
|
|
|
|
|
2015-09-01 06:37:52 +00:00
|
|
|
# pylint: disable=too-many-branches, too-many-statements, too-many-arguments
|
2015-09-01 06:12:00 +00:00
|
|
|
def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
|
2016-05-20 06:20:07 +00:00
|
|
|
verbose=False, skip_pip=False,
|
2015-09-04 22:22:42 +00:00
|
|
|
log_rotate_days=None):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Try to configure Home Assistant from a config dict.
|
2014-04-24 07:40:45 +00:00
|
|
|
|
2014-08-13 12:28:45 +00:00
|
|
|
Dynamically loads required components and its dependencies.
|
|
|
|
"""
|
|
|
|
if hass is None:
|
2015-08-17 03:44:46 +00:00
|
|
|
hass = core.HomeAssistant()
|
2015-08-30 01:11:24 +00:00
|
|
|
if config_dir is not None:
|
2015-08-30 02:19:52 +00:00
|
|
|
config_dir = os.path.abspath(config_dir)
|
|
|
|
hass.config.config_dir = config_dir
|
|
|
|
mount_local_lib_path(config_dir)
|
2014-04-24 07:40:45 +00:00
|
|
|
|
2016-05-08 05:24:04 +00:00
|
|
|
core_config = config.get(core.DOMAIN, {})
|
|
|
|
|
2016-03-28 01:48:51 +00:00
|
|
|
try:
|
|
|
|
process_ha_core_config(hass, config_util.CORE_CONFIG_SCHEMA(
|
2016-05-08 05:24:04 +00:00
|
|
|
core_config))
|
2016-03-28 01:48:51 +00:00
|
|
|
except vol.MultipleInvalid as ex:
|
2016-05-08 05:24:04 +00:00
|
|
|
cv.log_exception(_LOGGER, ex, 'homeassistant', core_config)
|
2016-03-28 01:48:51 +00:00
|
|
|
return None
|
|
|
|
|
2015-11-15 10:05:46 +00:00
|
|
|
process_ha_config_upgrade(hass)
|
2015-03-19 06:02:58 +00:00
|
|
|
|
2015-08-30 06:02:07 +00:00
|
|
|
if enable_log:
|
2016-05-20 06:20:07 +00:00
|
|
|
enable_logging(hass, verbose, log_rotate_days)
|
2015-01-18 06:23:07 +00:00
|
|
|
|
2015-09-04 21:50:57 +00:00
|
|
|
hass.config.skip_pip = skip_pip
|
|
|
|
if skip_pip:
|
|
|
|
_LOGGER.warning('Skipping pip installation of required modules. '
|
|
|
|
'This may cause issues.')
|
|
|
|
|
2015-01-30 07:56:04 +00:00
|
|
|
_ensure_loader_prepared(hass)
|
2014-11-28 23:34:42 +00:00
|
|
|
|
2014-08-13 12:28:45 +00:00
|
|
|
# Make a copy because we are mutating it.
|
|
|
|
# Convert it to defaultdict so components can always have config dict
|
2015-02-28 19:17:50 +00:00
|
|
|
# Convert values to dictionaries if they are None
|
2015-02-28 19:31:26 +00:00
|
|
|
config = defaultdict(
|
|
|
|
dict, {key: value or {} for key, value in config.items()})
|
2013-10-22 05:06:22 +00:00
|
|
|
|
2014-12-07 07:57:02 +00:00
|
|
|
# Filter out the repeating and common config section [homeassistant]
|
2015-09-29 06:09:05 +00:00
|
|
|
components = set(key.split(' ')[0] for key in config.keys()
|
|
|
|
if key != core.DOMAIN)
|
2014-10-22 15:12:32 +00:00
|
|
|
|
2014-12-17 05:46:02 +00:00
|
|
|
if not core_components.setup(hass, config):
|
2015-05-12 05:23:38 +00:00
|
|
|
_LOGGER.error('Home Assistant core failed to initialize. '
|
|
|
|
'Further initialization aborted.')
|
2014-12-17 05:46:02 +00:00
|
|
|
|
|
|
|
return hass
|
|
|
|
|
2015-05-12 05:23:38 +00:00
|
|
|
_LOGGER.info('Home Assistant core initialized')
|
2014-12-17 05:46:02 +00:00
|
|
|
|
2016-03-07 23:06:04 +00:00
|
|
|
# Give event decorators access to HASS
|
2016-01-24 22:46:05 +00:00
|
|
|
event_decorators.HASS = hass
|
2016-01-25 03:46:30 +00:00
|
|
|
service.HASS = hass
|
2016-01-24 22:46:05 +00:00
|
|
|
|
2014-08-13 12:28:45 +00:00
|
|
|
# Setup the components
|
2014-12-17 05:46:02 +00:00
|
|
|
for domain in loader.load_order_components(components):
|
2015-03-22 05:02:47 +00:00
|
|
|
_setup_component(hass, domain, config)
|
2013-10-13 17:42:22 +00:00
|
|
|
|
2014-08-13 12:28:45 +00:00
|
|
|
return hass
|
2013-10-22 05:06:22 +00:00
|
|
|
|
2014-01-24 01:46:29 +00:00
|
|
|
|
2016-05-20 06:20:07 +00:00
|
|
|
def from_config_file(config_path, hass=None, verbose=False, skip_pip=True,
|
|
|
|
log_rotate_days=None):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Read the configuration file and try to start all the functionality.
|
|
|
|
|
|
|
|
Will add functionality to 'hass' parameter if given,
|
2014-08-13 12:28:45 +00:00
|
|
|
instantiates a new Home Assistant object if 'hass' is not given.
|
|
|
|
"""
|
2014-09-21 02:19:39 +00:00
|
|
|
if hass is None:
|
2015-08-17 03:44:46 +00:00
|
|
|
hass = core.HomeAssistant()
|
2014-09-21 02:19:39 +00:00
|
|
|
|
2015-03-19 06:02:58 +00:00
|
|
|
# Set config dir to directory holding config file
|
2015-08-30 02:19:52 +00:00
|
|
|
config_dir = os.path.abspath(os.path.dirname(config_path))
|
|
|
|
hass.config.config_dir = config_dir
|
|
|
|
mount_local_lib_path(config_dir)
|
2014-09-21 02:19:39 +00:00
|
|
|
|
2016-05-20 06:20:07 +00:00
|
|
|
enable_logging(hass, verbose, log_rotate_days)
|
2015-08-30 06:02:07 +00:00
|
|
|
|
2016-04-09 22:25:01 +00:00
|
|
|
try:
|
|
|
|
config_dict = config_util.load_yaml_config_file(config_path)
|
|
|
|
except HomeAssistantError:
|
|
|
|
return None
|
2013-10-13 17:42:22 +00:00
|
|
|
|
2015-09-04 21:50:57 +00:00
|
|
|
return from_config_dict(config_dict, hass, enable_log=False,
|
|
|
|
skip_pip=skip_pip)
|
2015-01-18 06:23:07 +00:00
|
|
|
|
|
|
|
|
2016-05-20 06:20:07 +00:00
|
|
|
def enable_logging(hass, verbose=False, log_rotate_days=None):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Setup the logging."""
|
2016-05-20 06:20:07 +00:00
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)s) "
|
|
|
|
"[%(name)s] %(message)s%(reset)s")
|
|
|
|
try:
|
|
|
|
from colorlog import ColoredFormatter
|
|
|
|
logging.getLogger().handlers[0].setFormatter(ColoredFormatter(
|
|
|
|
fmt,
|
|
|
|
datefmt='%y-%m-%d %H:%M:%S',
|
|
|
|
reset=True,
|
|
|
|
log_colors={
|
|
|
|
'DEBUG': 'cyan',
|
|
|
|
'INFO': 'green',
|
|
|
|
'WARNING': 'yellow',
|
|
|
|
'ERROR': 'red',
|
|
|
|
'CRITICAL': 'red',
|
|
|
|
}
|
|
|
|
))
|
|
|
|
except ImportError:
|
|
|
|
pass
|
2015-01-18 06:23:07 +00:00
|
|
|
|
|
|
|
# Log errors to a file if we have write access to file or config dir
|
2015-11-07 09:44:02 +00:00
|
|
|
err_log_path = hass.config.path(ERROR_LOG_FILENAME)
|
2015-01-18 06:23:07 +00:00
|
|
|
err_path_exists = os.path.isfile(err_log_path)
|
|
|
|
|
|
|
|
# Check if we can write to the error log if it exists or that
|
|
|
|
# we can create files in the containing directory if not.
|
|
|
|
if (err_path_exists and os.access(err_log_path, os.W_OK)) or \
|
2015-03-19 06:02:58 +00:00
|
|
|
(not err_path_exists and os.access(hass.config.config_dir, os.W_OK)):
|
2015-01-18 06:23:07 +00:00
|
|
|
|
2015-09-04 22:22:42 +00:00
|
|
|
if log_rotate_days:
|
|
|
|
err_handler = logging.handlers.TimedRotatingFileHandler(
|
|
|
|
err_log_path, when='midnight', backupCount=log_rotate_days)
|
|
|
|
else:
|
|
|
|
err_handler = logging.FileHandler(
|
|
|
|
err_log_path, mode='w', delay=True)
|
2015-01-18 06:23:07 +00:00
|
|
|
|
2015-09-01 06:12:00 +00:00
|
|
|
err_handler.setLevel(logging.INFO if verbose else logging.WARNING)
|
2015-01-18 06:23:07 +00:00
|
|
|
err_handler.setFormatter(
|
|
|
|
logging.Formatter('%(asctime)s %(name)s: %(message)s',
|
2015-06-11 13:01:11 +00:00
|
|
|
datefmt='%y-%m-%d %H:%M:%S'))
|
2015-09-01 06:12:00 +00:00
|
|
|
logger = logging.getLogger('')
|
|
|
|
logger.addHandler(err_handler)
|
2015-12-23 02:39:46 +00:00
|
|
|
logger.setLevel(logging.INFO)
|
2015-01-18 06:23:07 +00:00
|
|
|
|
|
|
|
else:
|
|
|
|
_LOGGER.error(
|
2015-05-12 05:23:38 +00:00
|
|
|
'Unable to setup error log %s (access denied)', err_log_path)
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2015-01-30 16:26:06 +00:00
|
|
|
|
2015-11-15 10:05:46 +00:00
|
|
|
def process_ha_config_upgrade(hass):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Upgrade config if necessary."""
|
2015-11-15 10:05:46 +00:00
|
|
|
version_path = hass.config.path('.HA_VERSION')
|
|
|
|
|
|
|
|
try:
|
|
|
|
with open(version_path, 'rt') as inp:
|
|
|
|
conf_version = inp.readline().strip()
|
|
|
|
except FileNotFoundError:
|
|
|
|
# Last version to not have this file
|
|
|
|
conf_version = '0.7.7'
|
|
|
|
|
|
|
|
if conf_version == __version__:
|
|
|
|
return
|
|
|
|
|
|
|
|
_LOGGER.info('Upgrading config directory from %s to %s', conf_version,
|
|
|
|
__version__)
|
|
|
|
|
2016-04-12 03:07:50 +00:00
|
|
|
# This was where dependencies were installed before v0.18
|
|
|
|
# Probably should keep this around until ~v0.20.
|
2015-11-15 10:16:52 +00:00
|
|
|
lib_path = hass.config.path('lib')
|
|
|
|
if os.path.isdir(lib_path):
|
|
|
|
shutil.rmtree(lib_path)
|
2015-11-15 10:05:46 +00:00
|
|
|
|
2016-04-12 03:07:50 +00:00
|
|
|
lib_path = hass.config.path('deps')
|
|
|
|
if os.path.isdir(lib_path):
|
|
|
|
shutil.rmtree(lib_path)
|
|
|
|
|
2015-11-15 10:05:46 +00:00
|
|
|
with open(version_path, 'wt') as outp:
|
|
|
|
outp.write(__version__)
|
|
|
|
|
|
|
|
|
2015-03-19 06:02:58 +00:00
|
|
|
def process_ha_core_config(hass, config):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Process the [homeassistant] section from the config."""
|
2015-04-26 17:05:01 +00:00
|
|
|
hac = hass.config
|
|
|
|
|
2015-04-29 02:12:05 +00:00
|
|
|
def set_time_zone(time_zone_str):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Helper method to set time zone."""
|
2015-04-29 02:12:05 +00:00
|
|
|
if time_zone_str is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
time_zone = date_util.get_time_zone(time_zone_str)
|
|
|
|
|
|
|
|
if time_zone:
|
|
|
|
hac.time_zone = time_zone
|
|
|
|
date_util.set_default_time_zone(time_zone)
|
|
|
|
else:
|
2015-05-12 05:23:38 +00:00
|
|
|
_LOGGER.error('Received invalid time zone %s', time_zone_str)
|
2015-04-29 02:12:05 +00:00
|
|
|
|
2016-03-28 01:48:51 +00:00
|
|
|
for key, attr in ((CONF_LATITUDE, 'latitude'),
|
|
|
|
(CONF_LONGITUDE, 'longitude'),
|
|
|
|
(CONF_NAME, 'location_name')):
|
2015-03-19 06:02:58 +00:00
|
|
|
if key in config:
|
2016-03-28 01:48:51 +00:00
|
|
|
setattr(hac, attr, config[key])
|
2015-04-29 02:12:05 +00:00
|
|
|
|
2016-03-28 01:48:51 +00:00
|
|
|
if CONF_TIME_ZONE in config:
|
|
|
|
set_time_zone(config.get(CONF_TIME_ZONE))
|
2015-06-03 04:31:50 +00:00
|
|
|
|
2016-06-22 16:13:18 +00:00
|
|
|
entity.set_customize(config.get(CONF_CUSTOMIZE))
|
2015-04-15 02:57:32 +00:00
|
|
|
|
2015-03-19 06:02:58 +00:00
|
|
|
if CONF_TEMPERATURE_UNIT in config:
|
2016-03-28 01:48:51 +00:00
|
|
|
hac.temperature_unit = config[CONF_TEMPERATURE_UNIT]
|
2015-04-26 17:05:01 +00:00
|
|
|
|
|
|
|
# If we miss some of the needed values, auto detect them
|
2015-04-29 02:12:05 +00:00
|
|
|
if None not in (
|
|
|
|
hac.latitude, hac.longitude, hac.temperature_unit, hac.time_zone):
|
2015-04-26 17:05:01 +00:00
|
|
|
return
|
|
|
|
|
2016-03-28 01:48:51 +00:00
|
|
|
_LOGGER.warning('Incomplete core config. Auto detecting location and '
|
|
|
|
'temperature unit')
|
2015-04-26 17:05:01 +00:00
|
|
|
|
2015-07-07 07:00:21 +00:00
|
|
|
info = loc_util.detect_location_info()
|
2015-04-26 17:05:01 +00:00
|
|
|
|
|
|
|
if info is None:
|
|
|
|
_LOGGER.error('Could not detect location information')
|
|
|
|
return
|
|
|
|
|
|
|
|
if hac.latitude is None and hac.longitude is None:
|
|
|
|
hac.latitude = info.latitude
|
|
|
|
hac.longitude = info.longitude
|
|
|
|
|
|
|
|
if hac.temperature_unit is None:
|
|
|
|
if info.use_fahrenheit:
|
|
|
|
hac.temperature_unit = TEMP_FAHRENHEIT
|
|
|
|
else:
|
2016-04-20 03:30:44 +00:00
|
|
|
hac.temperature_unit = TEMP_CELSIUS
|
2015-04-26 17:05:01 +00:00
|
|
|
|
|
|
|
if hac.location_name is None:
|
|
|
|
hac.location_name = info.city
|
2015-03-19 06:02:58 +00:00
|
|
|
|
2015-04-26 17:05:01 +00:00
|
|
|
if hac.time_zone is None:
|
2015-04-29 02:12:05 +00:00
|
|
|
set_time_zone(info.time_zone)
|
2015-03-19 06:02:58 +00:00
|
|
|
|
|
|
|
|
2015-01-30 07:56:04 +00:00
|
|
|
def _ensure_loader_prepared(hass):
|
2016-03-07 23:06:04 +00:00
|
|
|
"""Ensure Home Assistant loader is prepared."""
|
2015-01-30 07:56:04 +00:00
|
|
|
if not loader.PREPARED:
|
|
|
|
loader.prepare(hass)
|