Skip to content

Commit

Permalink
Move conf code from bootstrap to config
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Jun 27, 2016
1 parent 2591418 commit 659ebc6
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 218 deletions.
127 changes: 13 additions & 114 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import logging
import logging.handlers
import os
import shutil
import sys
from collections import defaultdict
from threading import RLock
Expand All @@ -12,21 +11,15 @@

import homeassistant.components as core_components
from homeassistant.components import group, persistent_notification
import homeassistant.config as config_util
import homeassistant.config as conf_util
import homeassistant.core as core
import homeassistant.helpers.config_validation as cv
import homeassistant.loader as loader
import homeassistant.util.dt as date_util
import homeassistant.util.location as loc_util
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,
TEMP_CELSIUS, TEMP_FAHRENHEIT, PLATFORM_FORMAT, __version__)
from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import (
event_decorators, service, config_per_platform, extract_domain_configs,
entity)
event_decorators, service, config_per_platform, extract_domain_configs)

_LOGGER = logging.getLogger(__name__)
_SETUP_LOCK = RLock()
Expand Down Expand Up @@ -208,11 +201,6 @@ def prepare_setup_platform(hass, config, domain, platform_name):
return platform


def mount_local_lib_path(config_dir):
"""Add local library to Python Path."""
sys.path.insert(0, os.path.join(config_dir, 'deps'))


# pylint: disable=too-many-branches, too-many-statements, too-many-arguments
def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
verbose=False, skip_pip=False,
Expand All @@ -226,18 +214,17 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
if config_dir is not None:
config_dir = os.path.abspath(config_dir)
hass.config.config_dir = config_dir
mount_local_lib_path(config_dir)
_mount_local_lib_path(config_dir)

core_config = config.get(core.DOMAIN, {})

try:
process_ha_core_config(hass, config_util.CORE_CONFIG_SCHEMA(
core_config))
conf_util.process_ha_core_config(hass, core_config)
except vol.MultipleInvalid as ex:
cv.log_exception(_LOGGER, ex, 'homeassistant', core_config)
return None

process_ha_config_upgrade(hass)
conf_util.process_ha_config_upgrade(hass)

if enable_log:
enable_logging(hass, verbose, log_rotate_days)
Expand Down Expand Up @@ -292,12 +279,12 @@ def from_config_file(config_path, hass=None, verbose=False, skip_pip=True,
# Set config dir to directory holding config file
config_dir = os.path.abspath(os.path.dirname(config_path))
hass.config.config_dir = config_dir
mount_local_lib_path(config_dir)
_mount_local_lib_path(config_dir)

enable_logging(hass, verbose, log_rotate_days)

try:
config_dict = config_util.load_yaml_config_file(config_path)
config_dict = conf_util.load_yaml_config_file(config_path)
except HomeAssistantError:
return None

Expand Down Expand Up @@ -356,100 +343,12 @@ def enable_logging(hass, verbose=False, log_rotate_days=None):
'Unable to setup error log %s (access denied)', err_log_path)


def process_ha_config_upgrade(hass):
"""Upgrade config if necessary."""
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__)

# This was where dependencies were installed before v0.18
# Probably should keep this around until ~v0.20.
lib_path = hass.config.path('lib')
if os.path.isdir(lib_path):
shutil.rmtree(lib_path)

lib_path = hass.config.path('deps')
if os.path.isdir(lib_path):
shutil.rmtree(lib_path)

with open(version_path, 'wt') as outp:
outp.write(__version__)


def process_ha_core_config(hass, config):
"""Process the [homeassistant] section from the config."""
hac = hass.config

def set_time_zone(time_zone_str):
"""Helper method to set time zone."""
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:
_LOGGER.error('Received invalid time zone %s', time_zone_str)

for key, attr in ((CONF_LATITUDE, 'latitude'),
(CONF_LONGITUDE, 'longitude'),
(CONF_NAME, 'location_name')):
if key in config:
setattr(hac, attr, config[key])

if CONF_TIME_ZONE in config:
set_time_zone(config.get(CONF_TIME_ZONE))

entity.set_customize(config.get(CONF_CUSTOMIZE))

if CONF_TEMPERATURE_UNIT in config:
hac.temperature_unit = config[CONF_TEMPERATURE_UNIT]

# If we miss some of the needed values, auto detect them
if None not in (
hac.latitude, hac.longitude, hac.temperature_unit, hac.time_zone):
return

_LOGGER.warning('Incomplete core config. Auto detecting location and '
'temperature unit')

info = loc_util.detect_location_info()

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:
hac.temperature_unit = TEMP_CELSIUS

if hac.location_name is None:
hac.location_name = info.city

if hac.time_zone is None:
set_time_zone(info.time_zone)


def _ensure_loader_prepared(hass):
"""Ensure Home Assistant loader is prepared."""
if not loader.PREPARED:
loader.prepare(hass)


def _mount_local_lib_path(config_dir):
"""Add local library to Python Path."""
sys.path.insert(0, os.path.join(config_dir, 'deps'))
8 changes: 4 additions & 4 deletions homeassistant/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,16 @@ def handle_turn_service(service):
def handle_reload_config(call):
"""Service handler for reloading core config."""
from homeassistant.exceptions import HomeAssistantError
from homeassistant import config, bootstrap
from homeassistant import config as conf_util

try:
path = config.find_config_file(hass.config.config_dir)
conf = config.load_yaml_config_file(path)
path = conf_util.find_config_file(hass.config.config_dir)
conf = conf_util.load_yaml_config_file(path)
except HomeAssistantError as err:
_LOGGER.error(err)
return

bootstrap.process_ha_core_config(hass, conf.get(ha.DOMAIN) or {})
conf_util.process_ha_core_config(hass, conf.get(ha.DOMAIN) or {})

hass.services.register(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG,
handle_reload_config)
Expand Down
115 changes: 111 additions & 4 deletions homeassistant/config.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
"""Module to help with parsing and generating configuration files."""
import logging
import os
import shutil
from types import MappingProxyType

import voluptuous as vol

import homeassistant.util.location as loc_util
from homeassistant.const import (
CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_TEMPERATURE_UNIT,
CONF_TIME_ZONE, CONF_CUSTOMIZE, CONF_ELEVATION)
CONF_TIME_ZONE, CONF_CUSTOMIZE, CONF_ELEVATION, TEMP_FAHRENHEIT,
TEMP_CELSIUS, __version__)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.yaml import load_yaml
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import valid_entity_id
from homeassistant.helpers.entity import valid_entity_id, set_customize
from homeassistant.util import dt as date_util, location as loc_util

_LOGGER = logging.getLogger(__name__)

Expand All @@ -26,7 +28,7 @@
(CONF_LATITUDE, None, 'latitude', 'Location required to calculate the time'
' the sun rises and sets'),
(CONF_LONGITUDE, None, 'longitude', None),
(CONF_ELEVATION, 0, 'elevation', 'Impacts weather/sunrise data'),
(CONF_ELEVATION, 0, None, 'Impacts weather/sunrise data'),
(CONF_TEMPERATURE_UNIT, 'C', None, 'C for Celsius, F for Fahrenheit'),
(CONF_TIME_ZONE, 'UTC', 'time_zone', 'Pick yours from here: http://en.wiki'
'pedia.org/wiki/List_of_tz_database_time_zones'),
Expand Down Expand Up @@ -113,6 +115,10 @@ def create_default_config(config_dir, detect_location=True):
continue
info[attr] = getattr(location_info, prop) or default

if location_info.latitude and location_info.longitude:
info[CONF_ELEVATION] = loc_util.elevation(location_info.latitude,
location_info.longitude)

# Writing files with YAML does not create the most human readable results
# So we're hard coding a YAML template.
try:
Expand Down Expand Up @@ -157,3 +163,104 @@ def load_yaml_config_file(config_path):
raise HomeAssistantError(msg)

return conf_dict


def process_ha_config_upgrade(hass):
"""Upgrade config if necessary."""
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__)

lib_path = hass.config.path('deps')
if os.path.isdir(lib_path):
shutil.rmtree(lib_path)

with open(version_path, 'wt') as outp:
outp.write(__version__)


def process_ha_core_config(hass, config):
"""Process the [homeassistant] section from the config."""
config = CORE_CONFIG_SCHEMA(config)
hac = hass.config

def set_time_zone(time_zone_str):
"""Helper method to set time zone."""
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:
_LOGGER.error('Received invalid time zone %s', time_zone_str)

for key, attr in ((CONF_LATITUDE, 'latitude'),
(CONF_LONGITUDE, 'longitude'),
(CONF_NAME, 'location_name'),
(CONF_ELEVATION, 'elevation')):
if key in config:
setattr(hac, attr, config[key])

if CONF_TIME_ZONE in config:
set_time_zone(config.get(CONF_TIME_ZONE))

set_customize(config.get(CONF_CUSTOMIZE))

if CONF_TEMPERATURE_UNIT in config:
hac.temperature_unit = config[CONF_TEMPERATURE_UNIT]

discovered = []

# If we miss some of the needed values, auto detect them
if None in (hac.latitude, hac.longitude, hac.temperature_unit,
hac.time_zone):
info = loc_util.detect_location_info()

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
discovered.append(('latitude', hac.latitude))
discovered.append(('longitude', hac.longitude))

if hac.temperature_unit is None:
if info.use_fahrenheit:
hac.temperature_unit = TEMP_FAHRENHEIT
else:
hac.temperature_unit = TEMP_CELSIUS
discovered.append(('temperature_unit',
'F' if info.use_fahrenheit else 'C'))

if hac.location_name is None:
hac.location_name = info.city
discovered.append(('name', info.city))

if hac.time_zone is None:
set_time_zone(info.time_zone)
discovered.append(('time_zone', info.time_zone))

if hac.elevation is None:
elevation = loc_util.elevation(hac.latitude, hac.longitude)
hac.elevation = elevation
discovered.append(('elevation', elevation))

_LOGGER.warning(
'Incomplete core config. Auto detected %s',
', '.join('{}: {}'.format(key, val) for key, val in discovered))
4 changes: 1 addition & 3 deletions homeassistant/util/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
LocationInfo = collections.namedtuple(
"LocationInfo",
['ip', 'country_code', 'country_name', 'region_code', 'region_name',
'city', 'zip_code', 'time_zone', 'latitude', 'longitude', 'elevation',
'city', 'zip_code', 'time_zone', 'latitude', 'longitude',
'use_fahrenheit'])


Expand All @@ -47,8 +47,6 @@ def detect_location_info():
data['use_fahrenheit'] = data['country_code'] in (
'BS', 'BZ', 'KY', 'PW', 'US', 'AS', 'VI')

data['elevation'] = elevation(data['latitude'], data['longitude'])

return LocationInfo(**data)


Expand Down
2 changes: 1 addition & 1 deletion tests/components/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def test_reload_core_conf(self):
assert state.attributes.get('hello') == 'world'

@patch('homeassistant.components._LOGGER.error')
@patch('homeassistant.bootstrap.process_ha_core_config')
@patch('homeassistant.config.process_ha_core_config')
def test_reload_core_with_wrong_conf(self, mock_process, mock_error):
"""Test reload core conf service."""
with TemporaryDirectory() as conf_dir:
Expand Down
Loading

0 comments on commit 659ebc6

Please sign in to comment.