Exemple #1
0
def test_merge_once_only_keys(merge_log_err, hass):
    """Test if we have a merge for a comp that may occur only once. Keys."""
    packages = {'pack_2': {'api': {
        'key_3': 3,
    }}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': {
            'key_1': 1,
            'key_2': 2,
        }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert config['api'] == {'key_1': 1, 'key_2': 2, 'key_3': 3, }

    # Duplicate keys error
    packages = {'pack_2': {'api': {
        'key': 2,
    }}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': {'key': 1, }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert merge_log_err.call_count == 1
def test_merge_once_only_dictionaries(hass):
    """Test if we have a merge for a comp that may occur only once. Dicts."""
    packages = {'pack_2': {'api': {
        'dict_1': {
            'key_2': 2,
            'dict_1.1': {'key_1.2': 1.2, },
        },
        'dict_2': {'key_1': 1, },
        'dict_3': {},
    }}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': {
            'dict_1': {
                'key_1': 1,
                'dict_1.1': {'key_1.1': 1.1, }
            },
        }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert config['api'] == {
        'dict_1': {
            'key_1': 1,
            'key_2': 2,
            'dict_1.1': {'key_1.1': 1.1, 'key_1.2': 1.2, },
        },
        'dict_2': {'key_1': 1, },
    }
def test_merge_duplicate_keys(merge_log_err, hass):
    """Test if keys in dicts are duplicates."""
    packages = {
        'pack_1': {'input_select': {'ib1': None}},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'input_select': {'ib1': 1},
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 1
    assert len(config) == 2
    assert len(config['input_select']) == 1
def test_merge_once_only(merge_log_err):
    """Test if we have a merge for a comp that may occur only once."""
    packages = {
        'pack_2': {
            'mqtt': {},
            'api': {},  # No config schema
        },
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'mqtt': {}, 'api': {}
    }
    config_util.merge_packages_config(config, packages)
    assert merge_log_err.call_count == 1
    assert len(config) == 3
def test_merge_split_component_definition(hass):
    """Test components with trailing description in packages are merged."""
    packages = {
        'pack_1': {'light one': {'l1': None}},
        'pack_2': {'light two': {'l2': None},
                   'light three': {'l3': None}},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
    }
    config_util.merge_packages_config(hass, config, packages)

    assert len(config) == 4
    assert len(config['light one']) == 1
    assert len(config['light two']) == 1
    assert len(config['light three']) == 1
def test_merge_try_falsy(merge_log_err, hass):
    """Ensure we dont add falsy items like empty OrderedDict() to list."""
    packages = {
        'pack_falsy_to_lst': {'automation': OrderedDict()},
        'pack_list2': {'light': OrderedDict()},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'automation': {'do': 'something'},
        'light': {'some': 'light'},
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 0
    assert len(config) == 3
    assert len(config['automation']) == 1
    assert len(config['light']) == 1
def test_merge_once_only_lists(hass):
    """Test if we have a merge for a comp that may occur only once. Lists."""
    packages = {'pack_2': {'api': {
        'list_1': ['item_2', 'item_3'],
        'list_2': ['item_1'],
        'list_3': [],
    }}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': {
            'list_1': ['item_1'],
        }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert config['api'] == {
        'list_1': ['item_1', 'item_2', 'item_3'],
        'list_2': ['item_1'],
    }
def test_merge_type_mismatch(merge_log_err, hass):
    """Test if we have a type mismatch for packages."""
    packages = {
        'pack_1': {'input_boolean': [{'ib1': None}]},
        'pack_11': {'input_select': {'ib1': None}},
        'pack_2': {'light': {'ib1': None}},  # light gets merged - ensure_list
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'input_boolean': {'ib2': None},
        'input_select': [{'ib2': None}],
        'light': [{'platform': 'two'}]
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 2
    assert len(config) == 4
    assert len(config['input_boolean']) == 1
    assert len(config['light']) == 2
def test_merge(merge_log_err):
    """Test if we can merge packages."""
    packages = {
        'pack_dict': {'input_boolean': {'ib1': None}},
        'pack_11': {'input_select': {'is1': None}},
        'pack_list': {'light': {'platform': 'test'}},
        'pack_list2': {'light': [{'platform': 'test'}]},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'input_boolean': {'ib2': None},
        'light': {'platform': 'test'}
    }
    config_util.merge_packages_config(config, packages)

    assert merge_log_err.call_count == 0
    assert len(config) == 4
    assert len(config['input_boolean']) == 2
    assert len(config['input_select']) == 1
    assert len(config['light']) == 3
Exemple #10
0
def test_merge(merge_log_err):
    """Test if we can merge packages."""
    packages = {
        'pack_dict': {'input_boolean': {'ib1': None}},
        'pack_11': {'input_select': {'is1': None}},
        'pack_list': {'light': {'platform': 'test'}},
        'pack_list2': {'light': [{'platform': 'test'}]},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'input_boolean': {'ib2': None},
        'light': {'platform': 'test'}
    }
    config_util.merge_packages_config(config, packages)

    assert merge_log_err.call_count == 0
    assert len(config) == 4
    assert len(config['input_boolean']) == 2
    assert len(config['input_select']) == 1
    assert len(config['light']) == 3
def test_merge_new(merge_log_err, hass):
    """Test adding new components to outer scope."""
    packages = {
        'pack_1': {'light': [{'platform': 'one'}]},
        'pack_11': {'input_select': {'ib1': None}},
        'pack_2': {
            'light': {'platform': 'one'},
            'panel_custom': {'pan1': None},
            'api': {}},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 0
    assert 'api' in config
    assert len(config) == 5
    assert len(config['light']) == 2
    assert len(config['panel_custom']) == 1
Exemple #12
0
def test_merge_new(merge_log_err, hass):
    """Test adding new components to outer scope."""
    packages = {
        'pack_1': {'light': [{'platform': 'one'}]},
        'pack_11': {'input_select': {'ib1': None}},
        'pack_2': {
            'light': {'platform': 'one'},
            'panel_custom': {'pan1': None},
            'api': {}},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 0
    assert 'api' in config
    assert len(config) == 5
    assert len(config['light']) == 2
    assert len(config['panel_custom']) == 1
def test_merge_once_only(merge_log_err):
    """Test if we have a merge for a comp that may occur only once."""
    packages = {
        'pack_1': {
            'homeassistant': {}
        },
        'pack_2': {
            'mqtt': {},
            'api': {},  # No config schema
        },
    }
    config = {
        config_util.CONF_CORE: {
            config_util.CONF_PACKAGES: packages
        },
        'mqtt': {},
        'api': {}
    }
    config_util.merge_packages_config(config, packages)
    assert merge_log_err.call_count == 3
    assert len(config) == 3
Exemple #14
0
def test_merge_once_only_keys(merge_log_err, hass):
    """Test if we have a merge for a comp that may occur only once. Keys."""
    packages = {'pack_2': {'api': None}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': None,
    }
    config_util.merge_packages_config(hass, config, packages)
    assert config['api'] == OrderedDict()

    packages = {'pack_2': {'api': {
        'key_3': 3,
    }}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': {
            'key_1': 1,
            'key_2': 2,
        }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert config['api'] == {'key_1': 1, 'key_2': 2, 'key_3': 3, }

    # Duplicate keys error
    packages = {'pack_2': {'api': {
        'key': 2,
    }}}
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'api': {'key': 1, }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert merge_log_err.call_count == 1
def test_merge_type_mismatch(merge_log_err):
    """Test if we have a type mismatch for packages."""
    packages = {
        'pack_1': {
            'input_boolean': [{
                'ib1': None
            }]
        },
        'pack_11': {
            'input_select': {
                'ib1': None
            }
        },
        'pack_2': {
            'light': {
                'ib1': None
            }
        },  # light gets merged - ensure_list
    }
    config = {
        config_util.CONF_CORE: {
            config_util.CONF_PACKAGES: packages
        },
        'input_boolean': {
            'ib2': None
        },
        'input_select': [{
            'ib2': None
        }],
        'light': [{
            'platform': 'two'
        }]
    }
    config_util.merge_packages_config(config, packages)

    assert merge_log_err.call_count == 2
    assert len(config) == 4
    assert len(config['input_boolean']) == 1
    assert len(config['light']) == 2
Exemple #16
0
def test_merge(merge_log_err, hass):
    """Test if we can merge packages."""
    packages = {
        'pack_dict': {'input_boolean': {'ib1': None}},
        'pack_11': {'input_select': {'is1': None}},
        'pack_list': {'light': {'platform': 'test'}},
        'pack_list2': {'light': [{'platform': 'test'}]},
        'pack_none': {'wake_on_lan': None},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'input_boolean': {'ib2': None},
        'light': {'platform': 'test'}
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 0
    assert len(config) == 5
    assert len(config['input_boolean']) == 2
    assert len(config['input_select']) == 1
    assert len(config['light']) == 3
    assert isinstance(config['wake_on_lan'], OrderedDict)
def test_merge_duplicate_keys(merge_log_err):
    """Test if keys in dicts are duplicates."""
    packages = {
        'pack_1': {
            'input_select': {
                'ib1': None
            }
        },
    }
    config = {
        config_util.CONF_CORE: {
            config_util.CONF_PACKAGES: packages
        },
        'input_select': {
            'ib1': None
        },
    }
    config_util.merge_packages_config(config, packages)

    assert merge_log_err.call_count == 1
    assert len(config) == 2
    assert len(config['input_select']) == 1
def test_merge(merge_log_err, hass):
    """Test if we can merge packages."""
    packages = {
        'pack_dict': {'input_boolean': {'ib1': None}},
        'pack_11': {'input_select': {'is1': None}},
        'pack_list': {'light': {'platform': 'test'}},
        'pack_list2': {'light': [{'platform': 'test'}]},
        'pack_none': {'wake_on_lan': None},
    }
    config = {
        config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
        'input_boolean': {'ib2': None},
        'light': {'platform': 'test'}
    }
    config_util.merge_packages_config(hass, config, packages)

    assert merge_log_err.call_count == 0
    assert len(config) == 5
    assert len(config['input_boolean']) == 2
    assert len(config['input_select']) == 1
    assert len(config['light']) == 3
    assert isinstance(config['wake_on_lan'], OrderedDict)
Exemple #19
0
def test_merge_once_only_lists(hass):
    """Test if we have a merge for a comp that may occur only once. Lists."""
    packages = {
        'pack_2': {
            'api': {
                'list_1': ['item_2', 'item_3'],
                'list_2': ['item_1'],
                'list_3': [],
            }
        }
    }
    config = {
        config_util.CONF_CORE: {
            config_util.CONF_PACKAGES: packages
        },
        'api': {
            'list_1': ['item_1'],
        }
    }
    config_util.merge_packages_config(hass, config, packages)
    assert config['api'] == {
        'list_1': ['item_1', 'item_2', 'item_3'],
        'list_2': ['item_1'],
    }
Exemple #20
0
def async_from_config_dict(config: Dict[str, Any],
                           hass: core.HomeAssistant,
                           config_dir: Optional[str]=None,
                           enable_log: bool=True,
                           verbose: bool=False,
                           skip_pip: bool=False,
                           log_rotate_days: Any=None) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a config dict.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()
    hass.async_track_tasks()

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

    try:
        yield from conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        conf_util.async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    yield from hass.loop.run_in_executor(
        None, conf_util.process_ha_config_upgrade, hass)

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning('Skipping pip installation of required modules. '
                        'This may cause issues.')

    if not loader.PREPARED:
        yield from hass.loop.run_in_executor(None, loader.prepare, hass)

    # Merge packages
    conf_util.merge_packages_config(
        config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Make a copy because we are mutating it.
    # Use OrderedDict in case original one was one.
    # Convert values to dictionaries if they are None
    new_config = OrderedDict()
    for key, value in config.items():
        new_config[key] = value or {}
    config = new_config

    # Filter out the repeating and common config section [homeassistant]
    components = set(key.split(' ')[0] for key in config.keys()
                     if key != core.DOMAIN)

    # setup components
    # pylint: disable=not-an-iterable
    res = yield from core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error('Home Assistant core failed to initialize. '
                      'Further initialization aborted.')
        return hass

    yield from persistent_notification.async_setup(hass, config)

    _LOGGER.info('Home Assistant core initialized')

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_stop_track_tasks()

    stop = time()
    _LOGGER.info('Home Assistant initialized in %ss', round(stop-start, 2))

    async_register_signal_handling(hass)
    return hass
def async_from_config_dict(config: Dict[str, Any],
                           hass: core.HomeAssistant,
                           config_dir: Optional[str]=None,
                           enable_log: bool=True,
                           verbose: bool=False,
                           skip_pip: bool=False,
                           log_rotate_days: Any=None) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a config dict.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    hass.async_track_tasks()
    setup_lock = hass.data.get('setup_lock')
    if setup_lock is None:
        setup_lock = hass.data['setup_lock'] = asyncio.Lock(loop=hass.loop)

    yield from setup_lock.acquire()

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

    try:
        yield from conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    yield from hass.loop.run_in_executor(
        None, conf_util.process_ha_config_upgrade, hass)

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning('Skipping pip installation of required modules. '
                        'This may cause issues.')

    if not loader.PREPARED:
        yield from hass.loop.run_in_executor(None, loader.prepare, hass)

    # Merge packages
    conf_util.merge_packages_config(
        config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Make a copy because we are mutating it.
    # Use OrderedDict in case original one was one.
    # Convert values to dictionaries if they are None
    new_config = OrderedDict()
    for key, value in config.items():
        new_config[key] = value or {}
    config = new_config

    # Filter out the repeating and common config section [homeassistant]
    components = set(key.split(' ')[0] for key in config.keys()
                     if key != core.DOMAIN)

    # setup components
    # pylint: disable=not-an-iterable
    res = yield from core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error('Home Assistant core failed to initialize. '
                      'Further initialization aborted.')
        return hass

    yield from persistent_notification.async_setup(hass, config)

    _LOGGER.info('Home Assistant core initialized')

    # Give event decorators access to HASS
    event_decorators.HASS = hass
    service.HASS = hass

    # Setup the components
    dependency_blacklist = loader.DEPENDENCY_BLACKLIST - set(components)

    for domain in loader.load_order_components(components):
        if domain in dependency_blacklist:
            raise HomeAssistantError(
                '{} is not allowed to be a dependency'.format(domain))

        yield from _async_setup_component(hass, domain, config)

    setup_lock.release()

    yield from hass.async_stop_track_tasks()

    async_register_signal_handling(hass)
    return hass
def async_from_config_dict(config: Dict[str, Any],
                           hass: core.HomeAssistant,
                           config_dir: Optional[str]=None,
                           enable_log: bool=True,
                           verbose: bool=False,
                           skip_pip: bool=False,
                           log_rotate_days: Any=None) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a config dict.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    hass.async_track_tasks()
    setup_lock = hass.data.get('setup_lock')
    if setup_lock is None:
        setup_lock = hass.data['setup_lock'] = asyncio.Lock(loop=hass.loop)

    yield from setup_lock.acquire()

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

    try:
        yield from conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    yield from hass.loop.run_in_executor(None,
                                         conf_util.process_ha_config_upgrade,
                                         hass)

    if enable_log:
        enable_logging(hass, verbose, log_rotate_days)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning('Skipping pip installation of required modules. '
                        'This may cause issues.')

    if not loader.PREPARED:
        yield from hass.loop.run_in_executor(None, loader.prepare, hass)

    # Merge packages
    conf_util.merge_packages_config(
        config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Make a copy because we are mutating it.
    # Use OrderedDict in case original one was one.
    # Convert values to dictionaries if they are None
    new_config = OrderedDict()
    for key, value in config.items():
        new_config[key] = value or {}
    config = new_config

    # Filter out the repeating and common config section [homeassistant]
    components = set(
        key.split(' ')[0] for key in config.keys() if key != core.DOMAIN)

    # setup components
    # pylint: disable=not-an-iterable
    res = yield from core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error('Home Assistant core failed to initialize. '
                      'Further initialization aborted.')
        return hass

    yield from persistent_notification.async_setup(hass, config)

    _LOGGER.info('Home Assistant core initialized')

    # Give event decorators access to HASS
    event_decorators.HASS = hass
    service.HASS = hass

    # Setup the components
    for domain in loader.load_order_components(components):
        yield from _async_setup_component(hass, domain, config)

    setup_lock.release()

    yield from hass.async_stop_track_tasks()

    return hass
Exemple #23
0
async def async_from_config_dict(config: Dict[str, Any],
                                 hass: core.HomeAssistant,
                                 config_dir: Optional[str] = None,
                                 enable_log: bool = True,
                                 verbose: bool = False,
                                 skip_pip: bool = False,
                                 log_rotate_days: Any = None,
                                 log_file: Any = None,
                                 log_no_color: bool = False) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a configuration dictionary.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days, log_file,
                             log_no_color)

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

    try:
        await conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        conf_util.async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    await hass.async_add_executor_job(
        conf_util.process_ha_config_upgrade, hass)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning("Skipping pip installation of required modules. "
                        "This may cause issues")

    # Make a copy because we are mutating it.
    config = OrderedDict(config)

    # Merge packages
    conf_util.merge_packages_config(
        hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Ensure we have no None values after merge
    for key, value in config.items():
        if not value:
            config[key] = {}

    hass.config_entries = config_entries.ConfigEntries(hass, config)
    await hass.config_entries.async_load()

    # Filter out the repeating and common config section [homeassistant]
    components = set(key.split(' ')[0] for key in config.keys()
                     if key != core.DOMAIN)
    components.update(hass.config_entries.async_domains())

    # setup components
    res = await core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "further initialization aborted")
        return hass

    await persistent_notification.async_setup(hass, config)

    _LOGGER.info("Home Assistant core initialized")

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_create_task(async_setup_component(hass, component, config))

    await hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_create_task(async_setup_component(hass, component, config))

    await hass.async_block_till_done()

    stop = time()
    _LOGGER.info("Home Assistant initialized in %.2fs", stop-start)

    async_register_signal_handling(hass)
    return hass
Exemple #24
0
async def async_from_config_dict(config: Dict[str, Any],
                                 hass: core.HomeAssistant,
                                 config_dir: Optional[str] = None,
                                 enable_log: bool = True,
                                 verbose: bool = False,
                                 skip_pip: bool = False,
                                 log_rotate_days: Any = None,
                                 log_file: Any = None,
                                 log_no_color: bool = False) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a configuration dictionary.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days, log_file,
                             log_no_color)

    core_config = config.get(core.DOMAIN, {})
    has_api_password = bool((config.get('http') or {}).get('api_password'))
    has_trusted_networks = bool((config.get('http')
                                 or {}).get('trusted_networks'))

    try:
        await conf_util.async_process_ha_core_config(hass, core_config,
                                                     has_api_password,
                                                     has_trusted_networks)
    except vol.Invalid as config_err:
        conf_util.async_log_exception(config_err, 'homeassistant', core_config,
                                      hass)
        return None
    except HomeAssistantError:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "Further initialization aborted")
        return None

    await hass.async_add_executor_job(conf_util.process_ha_config_upgrade,
                                      hass)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning("Skipping pip installation of required modules. "
                        "This may cause issues")

    # Make a copy because we are mutating it.
    config = OrderedDict(config)

    # Merge packages
    conf_util.merge_packages_config(
        hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Ensure we have no None values after merge
    for key, value in config.items():
        if not value:
            config[key] = {}

    hass.config_entries = config_entries.ConfigEntries(hass, config)
    await hass.config_entries.async_load()

    # Filter out the repeating and common config section [homeassistant]
    components = set(
        key.split(' ')[0] for key in config.keys() if key != core.DOMAIN)
    components.update(hass.config_entries.async_domains())

    # setup components
    res = await core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "Further initialization aborted")
        return hass

    await persistent_notification.async_setup(hass, config)

    _LOGGER.info("Home Assistant core initialized")

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_create_task(async_setup_component(hass, component, config))

    await hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_create_task(async_setup_component(hass, component, config))

    await hass.async_block_till_done()

    stop = time()
    _LOGGER.info("Home Assistant initialized in %.2fs", stop - start)

    return hass
Exemple #25
0
def async_from_config_dict(config: Dict[str, Any],
                           hass: core.HomeAssistant,
                           config_dir: Optional[str] = None,
                           enable_log: bool = True,
                           verbose: bool = False,
                           skip_pip: bool = False,
                           log_rotate_days: Any = None,
                           log_file: Any = None) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a configuration dictionary.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days, log_file)

    if sys.version_info[:2] < (3, 5):
        _LOGGER.warning(
            'Python 3.4 support has been deprecated and will be removed in '
            'the beginning of 2018. Please upgrade Python or your operating '
            'system. More info: https://home-assistant.io/blog/2017/10/06/'
            'deprecating-python-3.4-support/'
        )

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

    try:
        yield from conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        conf_util.async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    yield from hass.async_add_job(conf_util.process_ha_config_upgrade, hass)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning("Skipping pip installation of required modules. "
                        "This may cause issues")

    if not loader.PREPARED:
        yield from hass.async_add_job(loader.prepare, hass)

    # Make a copy because we are mutating it.
    new_config = OrderedDict()
    for key, value in config.items():
        new_config[key] = value or {}
    config = new_config

    # Merge packages
    conf_util.merge_packages_config(
        config, core_config.get(conf_util.CONF_PACKAGES, {}))

    hass.config_entries = config_entries.ConfigEntries(hass, config)
    yield from hass.config_entries.async_load()

    # Filter out the repeating and common config section [homeassistant]
    components = set(key.split(' ')[0] for key in config.keys()
                     if key != core.DOMAIN)
    components.update(hass.config_entries.async_domains())

    # setup components
    # pylint: disable=not-an-iterable
    res = yield from core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "further initialization aborted")
        return hass

    yield from persistent_notification.async_setup(hass, config)

    _LOGGER.info("Home Assistant core initialized")

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    stop = time()
    _LOGGER.info("Home Assistant initialized in %.2fs", stop-start)

    async_register_signal_handling(hass)
    return hass
Exemple #26
0
async def async_from_config_dict(config: Dict[str, Any],
                                 hass: core.HomeAssistant,
                                 config_dir: Optional[str] = None,
                                 enable_log: bool = True,
                                 verbose: bool = False,
                                 skip_pip: bool = False,
                                 log_rotate_days: Any = None,
                                 log_file: Any = None,
                                 log_no_color: bool = False) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a configuration dictionary.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days, log_file,
                             log_no_color)

    core_config = config.get(core.DOMAIN, {})
    has_api_password = bool((config.get('http') or {}).get('api_password'))
    has_trusted_networks = bool((config.get('http') or {})
                                .get('trusted_networks'))

    try:
        await conf_util.async_process_ha_core_config(
            hass, core_config, has_api_password, has_trusted_networks)
    except vol.Invalid as config_err:
        conf_util.async_log_exception(
            config_err, 'homeassistant', core_config, hass)
        return None
    except HomeAssistantError:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "Further initialization aborted")
        return None

    await hass.async_add_executor_job(
        conf_util.process_ha_config_upgrade, hass)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning("Skipping pip installation of required modules. "
                        "This may cause issues")

    # Make a copy because we are mutating it.
    config = OrderedDict(config)

    # Merge packages
    conf_util.merge_packages_config(
        hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))

    hass.config_entries = config_entries.ConfigEntries(hass, config)
    await hass.config_entries.async_load()

    # Filter out the repeating and common config section [homeassistant]
    components = set(key.split(' ')[0] for key in config.keys()
                     if key != core.DOMAIN)
    components.update(hass.config_entries.async_domains())

    # Resolve all dependencies of all components.
    for component in list(components):
        try:
            components.update(loader.component_dependencies(hass, component))
        except loader.LoaderError:
            # Ignore it, or we'll break startup
            # It will be properly handled during setup.
            pass

    # setup components
    res = await core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "Further initialization aborted")
        return hass

    await persistent_notification.async_setup(hass, config)

    _LOGGER.info("Home Assistant core initialized")

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_create_task(async_setup_component(hass, component, config))

    await hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_create_task(async_setup_component(hass, component, config))

    await hass.async_block_till_done()

    stop = time()
    _LOGGER.info("Home Assistant initialized in %.2fs", stop-start)

    # TEMP: warn users for invalid slugs
    # Remove after 0.94 or 1.0
    if cv.INVALID_SLUGS_FOUND or cv.INVALID_ENTITY_IDS_FOUND:
        msg = []

        if cv.INVALID_ENTITY_IDS_FOUND:
            msg.append(
                "Your configuration contains invalid entity ID references. "
                "Please find and update the following. "
                "This will become a breaking change."
            )
            msg.append('\n'.join('- {} -> {}'.format(*item)
                                 for item
                                 in cv.INVALID_ENTITY_IDS_FOUND.items()))

        if cv.INVALID_SLUGS_FOUND:
            msg.append(
                "Your configuration contains invalid slugs. "
                "Please find and update the following. "
                "This will become a breaking change."
            )
            msg.append('\n'.join('- {} -> {}'.format(*item)
                                 for item in cv.INVALID_SLUGS_FOUND.items()))

        hass.components.persistent_notification.async_create(
            '\n\n'.join(msg), "Config Warning", "config_warning"
        )

    # TEMP: warn users of invalid extra keys
    # Remove after 0.92
    if cv.INVALID_EXTRA_KEYS_FOUND:
        msg = []
        msg.append(
            "Your configuration contains extra keys "
            "that the platform does not support (but were silently "
            "accepted before 0.88). Please find and remove the following."
            "This will become a breaking change."
        )
        msg.append('\n'.join('- {}'.format(it)
                             for it in cv.INVALID_EXTRA_KEYS_FOUND))

        hass.components.persistent_notification.async_create(
            '\n\n'.join(msg), "Config Warning", "config_warning"
        )

    return hass
def async_from_config_dict(config: Dict[str, Any],
                           hass: core.HomeAssistant,
                           config_dir: Optional[str]=None,
                           enable_log: bool=True,
                           verbose: bool=False,
                           skip_pip: bool=False,
                           log_rotate_days: Any=None,
                           log_file: Any=None) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a configuration dictionary.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days, log_file)

    if sys.version_info[:2] < (3, 5):
        _LOGGER.warning(
            'Python 3.4 support has been deprecated and will be removed in '
            'the beginning of 2018. Please upgrade Python or your operating '
            'system. More info: https://home-assistant.io/blog/2017/10/06/'
            'deprecating-python-3.4-support/'
        )

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

    try:
        yield from conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        conf_util.async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    yield from hass.async_add_job(conf_util.process_ha_config_upgrade, hass)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning("Skipping pip installation of required modules. "
                        "This may cause issues")

    if not loader.PREPARED:
        yield from hass.async_add_job(loader.prepare, hass)

    # Merge packages
    conf_util.merge_packages_config(
        config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Make a copy because we are mutating it.
    # Use OrderedDict in case original one was one.
    # Convert values to dictionaries if they are None
    new_config = OrderedDict()
    for key, value in config.items():
        new_config[key] = value or {}
    config = new_config

    # Filter out the repeating and common config section [homeassistant]
    components = set(key.split(' ')[0] for key in config.keys()
                     if key != core.DOMAIN)

    # setup components
    # pylint: disable=not-an-iterable
    res = yield from core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error("Home Assistant core failed to initialize. "
                      "further initialization aborted")
        return hass

    yield from persistent_notification.async_setup(hass, config)

    _LOGGER.info("Home Assistant core initialized")

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    stop = time()
    _LOGGER.info("Home Assistant initialized in %.2fs", stop-start)

    async_register_signal_handling(hass)
    return hass
def async_from_config_dict(config: Dict[str, Any],
                           hass: core.HomeAssistant,
                           config_dir: Optional[str]=None,
                           enable_log: bool=True,
                           verbose: bool=False,
                           skip_pip: bool=False,
                           log_rotate_days: Any=None) \
                           -> Optional[core.HomeAssistant]:
    """Try to configure Home Assistant from a config dict.

    Dynamically loads required components and its dependencies.
    This method is a coroutine.
    """
    start = time()
    core_config = config.get(core.DOMAIN, {})

    try:
        yield from conf_util.async_process_ha_core_config(hass, core_config)
    except vol.Invalid as ex:
        conf_util.async_log_exception(ex, 'homeassistant', core_config, hass)
        return None

    yield from hass.async_add_job(conf_util.process_ha_config_upgrade, hass)

    if enable_log:
        async_enable_logging(hass, verbose, log_rotate_days)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning('Skipping pip installation of required modules. '
                        'This may cause issues.')

    if not loader.PREPARED:
        yield from hass.async_add_job(loader.prepare, hass)

    # Merge packages
    conf_util.merge_packages_config(
        config, core_config.get(conf_util.CONF_PACKAGES, {}))

    # Make a copy because we are mutating it.
    # Use OrderedDict in case original one was one.
    # Convert values to dictionaries if they are None
    new_config = OrderedDict()
    for key, value in config.items():
        new_config[key] = value or {}
    config = new_config

    # Filter out the repeating and common config section [homeassistant]
    components = set(
        key.split(' ')[0] for key in config.keys() if key != core.DOMAIN)

    # setup components
    # pylint: disable=not-an-iterable
    res = yield from core_components.async_setup(hass, config)
    if not res:
        _LOGGER.error('Home Assistant core failed to initialize. '
                      'Further initialization aborted.')
        return hass

    yield from persistent_notification.async_setup(hass, config)

    _LOGGER.info('Home Assistant core initialized')

    # stage 1
    for component in components:
        if component not in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    # stage 2
    for component in components:
        if component in FIRST_INIT_COMPONENT:
            continue
        hass.async_add_job(async_setup_component(hass, component, config))

    yield from hass.async_block_till_done()

    stop = time()
    _LOGGER.info('Home Assistant initialized in %.2fs', stop - start)

    async_register_signal_handling(hass)
    return hass
Exemple #29
0
def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(_format_config_error(ex, domain, config), domain,
                         config)

    # Load configuration.yaml
    try:
        config_path = find_config_file(config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = load_yaml_config_file(config_path)
    except HomeAssistantError as err:
        return result.add_error("Error loading {}: {}".format(
            config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    merge_packages_config(hass, config, core_config.get(CONF_PACKAGES, {}),
                          _pack_error)
    del core_config[CONF_PACKAGES]

    # Ensure we have no None values after merge
    for key, value in config.items():
        if not value:
            config[key] = {}

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        component = loader.get_component(hass, domain)
        if not component:
            result.add_error("Component not found: {}".format(domain))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        if not hasattr(component, 'PLATFORM_SCHEMA'):
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component.PLATFORM_SCHEMA(p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = loader.get_platform(hass, domain, p_name)

            if platform is None:
                result.add_error("Platform not found: {}.{}".format(
                    domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(ex, '{}.{}'.format(domain, p_name),
                                p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result
def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(
            _format_config_error(ex, domain, config), domain, config)

    # Load configuration.yaml
    try:
        config_path = find_config_file(config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = load_yaml_config_file(config_path)
    except HomeAssistantError as err:
        return result.add_error(
            "Error loading {}: {}".format(config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    merge_packages_config(
        hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error)
    core_config.pop(CONF_PACKAGES, None)

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        component = loader.get_component(hass, domain)
        if not component:
            result.add_error("Component not found: {}".format(domain))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        if (not hasattr(component, 'PLATFORM_SCHEMA') and
                not hasattr(component, 'PLATFORM_SCHEMA_BASE')):
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                if hasattr(component, 'PLATFORM_SCHEMA_BASE'):
                    p_validated = \
                        component.PLATFORM_SCHEMA_BASE(  # type: ignore
                            p_config)
                else:
                    p_validated = component.PLATFORM_SCHEMA(  # type: ignore
                        p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = loader.get_platform(hass, domain, p_name)

            if platform is None:
                result.add_error(
                    "Platform not found: {}.{}".format(domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(
                        ex, '{}.{}'.format(domain, p_name), p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result