forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbootstrap.py
164 lines (118 loc) · 4.83 KB
/
bootstrap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""
homeassistant.bootstrap
~~~~~~~~~~~~~~~~~~~~~~~
Provides methods to bootstrap a home assistant instance.
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)
"""
import os
import configparser
import yaml
import io
import logging
from collections import defaultdict
import homeassistant
import homeassistant.loader as loader
import homeassistant.components as core_components
import homeassistant.components.group as group
from homeassistant.const import EVENT_COMPONENT_LOADED
_LOGGER = logging.getLogger(__name__)
ATTR_COMPONENT = "component"
def setup_component(hass, domain, config=None):
""" Setup a component for Home Assistant. """
# Check if already loaded
if domain in hass.components:
return
_ensure_loader_prepared(hass)
if config is None:
config = defaultdict(dict)
component = loader.get_component(domain)
try:
if component.setup(hass, config):
hass.components.append(component.DOMAIN)
# Assumption: if a component does not depend on groups
# it communicates with devices
if group.DOMAIN not in component.DEPENDENCIES:
hass.pool.add_worker()
hass.bus.fire(
EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN})
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
# pylint: disable=too-many-branches, too-many-statements
def from_config_dict(config, hass=None):
"""
Tries to configure Home Assistant from a config dict.
Dynamically loads required components and its dependencies.
"""
if hass is None:
hass = homeassistant.HomeAssistant()
enable_logging(hass)
_ensure_loader_prepared(hass)
# Make a copy because we are mutating it.
# Convert it to defaultdict so components can always have config dict
config = defaultdict(dict, config)
# Filter out the repeating and common config section [homeassistant]
components = (key for key in config.keys()
if ' ' not in key and key != homeassistant.DOMAIN)
if not core_components.setup(hass, config):
_LOGGER.error("Home Assistant core failed to initialize. "
"Further initialization aborted.")
return hass
_LOGGER.info("Home Assistant core initialized")
# Setup the components
for domain in loader.load_order_components(components):
setup_component(hass, domain, config)
return hass
def from_config_file(config_path, hass=None):
"""
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.
"""
if hass is None:
hass = homeassistant.HomeAssistant()
# Set config dir to directory holding config file
hass.config_dir = os.path.abspath(os.path.dirname(config_path))
config_dict = {}
# check config file type
if(os.path.splitext(config_path)[1] == '.yaml'):
# 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
return from_config_dict(config_dict, hass)
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)
def _ensure_loader_prepared(hass):
""" Ensure Home Assistant loader is prepared. """
if not loader.PREPARED:
loader.prepare(hass)