2013-10-13 17:42:22 +00:00
|
|
|
"""
|
2014-11-05 07:34:19 +00:00
|
|
|
homeassistant.bootstrap
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
2013-10-13 17:42:22 +00:00
|
|
|
Provides methods to bootstrap a home assistant instance.
|
2014-04-24 07:40:45 +00:00
|
|
|
|
|
|
|
Each method will return a tuple (bus, statemachine).
|
|
|
|
|
|
|
|
After bootstrapping you can add your own components or
|
|
|
|
start by calling homeassistant.start_home_assistant(bus)
|
2013-10-13 17:42:22 +00:00
|
|
|
"""
|
|
|
|
|
2014-09-21 02:19:39 +00:00
|
|
|
import os
|
2014-04-14 07:10:24 +00:00
|
|
|
import configparser
|
2015-02-28 16:05:38 +00:00
|
|
|
import yaml
|
|
|
|
import io
|
2013-10-22 05:06:22 +00:00
|
|
|
import logging
|
2014-08-13 12:28:45 +00:00
|
|
|
from collections import defaultdict
|
2013-10-13 17:42:22 +00:00
|
|
|
|
2014-04-24 07:40:45 +00:00
|
|
|
import homeassistant
|
2014-11-05 07:34:19 +00:00
|
|
|
import homeassistant.loader as loader
|
2014-08-13 12:28:45 +00:00
|
|
|
import homeassistant.components as core_components
|
2015-01-15 07:18:44 +00:00
|
|
|
import homeassistant.components.group as group
|
2015-02-14 06:49:56 +00:00
|
|
|
from homeassistant.const import EVENT_COMPONENT_LOADED
|
2014-01-24 05:34:08 +00:00
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2015-02-14 06:49:56 +00:00
|
|
|
ATTR_COMPONENT = "component"
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
|
|
|
|
def setup_component(hass, domain, config=None):
|
|
|
|
""" Setup a component for Home Assistant. """
|
2015-01-30 07:56:04 +00:00
|
|
|
# Check if already loaded
|
|
|
|
if domain in hass.components:
|
|
|
|
return
|
|
|
|
|
|
|
|
_ensure_loader_prepared(hass)
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
if config is None:
|
|
|
|
config = defaultdict(dict)
|
|
|
|
|
|
|
|
component = loader.get_component(domain)
|
|
|
|
|
|
|
|
try:
|
|
|
|
if component.setup(hass, config):
|
|
|
|
hass.components.append(component.DOMAIN)
|
|
|
|
|
2015-01-15 07:18:44 +00:00
|
|
|
# Assumption: if a component does not depend on groups
|
|
|
|
# it communicates with devices
|
|
|
|
if group.DOMAIN not in component.DEPENDENCIES:
|
|
|
|
hass.pool.add_worker()
|
|
|
|
|
2015-02-14 06:49:56 +00:00
|
|
|
hass.bus.fire(
|
|
|
|
EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN})
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
else:
|
|
|
|
_LOGGER.error("component %s failed to initialize", domain)
|
|
|
|
|
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
_LOGGER.exception("Error during setup of component %s", domain)
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2014-10-25 06:44:00 +00:00
|
|
|
# pylint: disable=too-many-branches, too-many-statements
|
2014-08-13 12:28:45 +00:00
|
|
|
def from_config_dict(config, hass=None):
|
|
|
|
"""
|
|
|
|
Tries 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:
|
|
|
|
hass = homeassistant.HomeAssistant()
|
2014-04-24 07:40:45 +00:00
|
|
|
|
2015-01-18 06:23:07 +00:00
|
|
|
enable_logging(hass)
|
|
|
|
|
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
|
|
|
|
config = defaultdict(dict, config)
|
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]
|
|
|
|
components = (key for key in config.keys()
|
|
|
|
if ' ' not in key and key != homeassistant.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-01-09 08:07:58 +00:00
|
|
|
_LOGGER.error("Home Assistant core failed to initialize. "
|
|
|
|
"Further initialization aborted.")
|
2014-12-17 05:46:02 +00:00
|
|
|
|
|
|
|
return hass
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
_LOGGER.info("Home Assistant core initialized")
|
2014-12-17 05:46:02 +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-01-15 07:18:44 +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
|
|
|
|
2015-01-18 06:23:07 +00:00
|
|
|
def from_config_file(config_path, hass=None):
|
2014-08-13 12:28:45 +00:00
|
|
|
"""
|
|
|
|
Reads the configuration file and tries to start all the required
|
|
|
|
functionality. Will add functionality to 'hass' parameter if given,
|
|
|
|
instantiates a new Home Assistant object if 'hass' is not given.
|
|
|
|
"""
|
2014-09-21 02:19:39 +00:00
|
|
|
if hass is None:
|
|
|
|
hass = homeassistant.HomeAssistant()
|
|
|
|
|
|
|
|
# Set config dir to directory holding config file
|
2014-09-23 02:44:26 +00:00
|
|
|
hass.config_dir = os.path.abspath(os.path.dirname(config_path))
|
2014-09-21 02:19:39 +00:00
|
|
|
|
2015-02-28 16:42:23 +00:00
|
|
|
config_dict = {}
|
2015-02-28 15:56:58 +00:00
|
|
|
# check config file type
|
2015-02-28 17:59:45 +00:00
|
|
|
if os.path.splitext(config_path)[1] == '.yaml':
|
2015-02-28 15:56:58 +00:00
|
|
|
# Read yaml
|
|
|
|
config_dict = yaml.load(io.open(config_path, 'r'))
|
|
|
|
else:
|
|
|
|
# Read config
|
|
|
|
config = configparser.ConfigParser()
|
|
|
|
config.read(config_path)
|
|
|
|
|
|
|
|
for section in config.sections():
|
|
|
|
config_dict[section] = {}
|
|
|
|
|
|
|
|
for key, val in config.items(section):
|
|
|
|
config_dict[section][key] = val
|
2013-10-13 17:42:22 +00:00
|
|
|
|
2014-08-13 12:28:45 +00:00
|
|
|
return from_config_dict(config_dict, hass)
|
2015-01-18 06:23:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
def enable_logging(hass):
|
|
|
|
""" Setup the logging for home assistant. """
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
|
|
# Log errors to a file if we have write access to file or config dir
|
|
|
|
err_log_path = hass.get_config_path("home-assistant.log")
|
|
|
|
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 \
|
|
|
|
(not err_path_exists and os.access(hass.config_dir, os.W_OK)):
|
|
|
|
|
|
|
|
err_handler = logging.FileHandler(
|
|
|
|
err_log_path, mode='w', delay=True)
|
|
|
|
|
|
|
|
err_handler.setLevel(logging.WARNING)
|
|
|
|
err_handler.setFormatter(
|
|
|
|
logging.Formatter('%(asctime)s %(name)s: %(message)s',
|
|
|
|
datefmt='%H:%M %d-%m-%y'))
|
|
|
|
logging.getLogger('').addHandler(err_handler)
|
|
|
|
|
|
|
|
else:
|
|
|
|
_LOGGER.error(
|
|
|
|
"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-01-30 07:56:04 +00:00
|
|
|
def _ensure_loader_prepared(hass):
|
|
|
|
""" Ensure Home Assistant loader is prepared. """
|
|
|
|
if not loader.PREPARED:
|
|
|
|
loader.prepare(hass)
|