def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = get_test_home_assistant()
        loader.prepare(self.hass)

        self.known_dev_path = self.hass.config.path(
            device_tracker.KNOWN_DEVICES_FILE)
示例#2
0
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)

    loader.prepare(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
示例#3
0
def get_test_home_assistant(num_threads=None):
    """Return a Home Assistant object pointing at test config dir."""
    loop = asyncio.new_event_loop()

    if num_threads:
        orig_num_threads = ha.MIN_WORKER_THREAD
        ha.MIN_WORKER_THREAD = num_threads

    hass = ha.HomeAssistant(loop)

    if num_threads:
        ha.MIN_WORKER_THREAD = orig_num_threads

    hass.config.location_name = 'test home'
    hass.config.config_dir = get_test_config_dir()
    hass.config.latitude = 32.87336
    hass.config.longitude = -117.22743
    hass.config.elevation = 0
    hass.config.time_zone = date_util.get_time_zone('US/Pacific')
    hass.config.units = METRIC_SYSTEM
    hass.config.skip_pip = True

    if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
        loader.prepare(hass)

    # FIXME should not be a daemon. Means hass.stop() not called in teardown
    stop_event = threading.Event()

    def run_loop():
        loop.run_forever()
        loop.close()
        stop_event.set()

    threading.Thread(name="LoopThread", target=run_loop, daemon=True).start()

    orig_start = hass.start
    orig_stop = hass.stop

    @asyncio.coroutine
    def fake_stop():
        yield None

    def start_hass():
        """Helper to start hass."""
        with patch.object(hass.loop, 'run_forever', return_value=None):
            with patch.object(hass, 'async_stop', return_value=fake_stop()):
                with patch.object(ha, 'async_create_timer', return_value=None):
                    with patch.object(ha, 'async_monitor_worker_pool',
                                      return_value=None):
                        orig_start()
                        hass.block_till_done()

    def stop_hass():
        orig_stop()
        stop_event.wait()

    hass.start = start_hass
    hass.stop = stop_hass

    return hass
    def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = get_test_home_assistant()
        loader.prepare(self.hass)

        self.known_dev_path = self.hass.get_config_path(
            device_tracker.KNOWN_DEVICES_FILE)
    def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = ha.HomeAssistant()
        loader.prepare(self.hass)
        self.assertTrue(comps.setup(self.hass, {}))

        self.hass.states.set('light.Bowl', comps.STATE_ON)
        self.hass.states.set('light.Ceiling', comps.STATE_OFF)
示例#6
0
    def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = ha.HomeAssistant()
        loader.prepare(self.hass)
        self.assertTrue(comps.setup(self.hass, {}))

        self.hass.states.set('light.Bowl', STATE_ON)
        self.hass.states.set('light.Ceiling', STATE_OFF)
    def setUp(self):  # pylint: disable=invalid-name
        self.hass = ha.HomeAssistant()
        loader.prepare(self.hass)
        self.calls = []

        def record_call(service):
            self.calls.append(service)

        self.hass.services.register('test', 'automation', record_call)
示例#8
0
    def setUp(self):  # pylint: disable=invalid-name
        self.hass = ha.HomeAssistant()
        loader.prepare(self.hass)
        self.calls = []

        def record_call(service):
            self.calls.append(service)

        self.hass.services.register('test', 'automation', record_call)
示例#9
0
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()

    logger = logging.getLogger(__name__)

    loader.prepare(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

    # We assume that all components that load before the group component loads
    # are components that poll devices. As their tasks are IO based, we will
    # add an extra worker for each of them.
    add_worker = True

    for domain in loader.load_order_components(components):
        component = loader.get_component(domain)

        try:
            if component.setup(hass, config):
                logger.info("component %s initialized", domain)

                add_worker = add_worker and domain != "group"

                if add_worker:
                    hass.pool.add_worker()

            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 hass
示例#10
0
    def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = get_test_home_assistant()
        loader.prepare(self.hass)

        self.hass.states.set('light.Bowl', STATE_ON)
        self.hass.states.set('light.Ceiling', STATE_OFF)
        self.hass.states.set('light.Kitchen', STATE_OFF)

        loader.get_component('group').setup_group(
            self.hass, 'test', ['light.Ceiling', 'light.Kitchen'])
示例#11
0
    def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = get_test_home_assistant()
        loader.prepare(self.hass)

        self.hass.states.set('light.Bowl', STATE_ON)
        self.hass.states.set('light.Ceiling', STATE_OFF)
        self.hass.states.set('light.Kitchen', STATE_OFF)

        loader.get_component('group').setup_group(
            self.hass, 'test', ['light.Ceiling', 'light.Kitchen'])
示例#12
0
    def setUp(self):  # pylint: disable=invalid-name
        self.hass = get_test_home_assistant()
        loader.prepare(self.hass)

        platform = loader.get_component("switch.test")

        platform.init()
        self.assertTrue(switch.setup(self.hass, {switch.DOMAIN: {CONF_PLATFORM: "test"}}))

        # Switch 1 is ON, switch 2 is OFF
        self.switch_1, self.switch_2, self.switch_3 = platform.DEVICES
    def setUp(self):  # pylint: disable=invalid-name
        self.hass = ha.HomeAssistant()
        loader.prepare(self.hass)
        loader.set_component('switch.test', mock_toggledevice_platform)

        mock_toggledevice_platform.init()
        self.assertTrue(switch.setup(
            self.hass, {switch.DOMAIN: {ha.CONF_TYPE: 'test'}}
        ))

        # Switch 1 is ON, switch 2 is OFF
        self.switch_1, self.switch_2, self.switch_3 = \
            mock_toggledevice_platform.get_switches(None, None)
    def setUp(self):  # pylint: disable=invalid-name
        self.hass = get_test_home_assistant()
        loader.prepare(self.hass)

        platform = loader.get_component('switch.test')

        platform.init()
        self.assertTrue(switch.setup(
            self.hass, {switch.DOMAIN: {CONF_PLATFORM: 'test'}}
        ))

        # Switch 1 is ON, switch 2 is OFF
        self.switch_1, self.switch_2, self.switch_3 = \
            platform.get_switches(None, None)
示例#15
0
    def setUp(self):  # pylint: disable=invalid-name
        self.hass = ha.HomeAssistant()
        loader.prepare(self.hass)
        loader.set_component('switch.test', mock_toggledevice_platform)

        mock_toggledevice_platform.init()
        self.assertTrue(
            switch.setup(self.hass, {switch.DOMAIN: {
                ha.CONF_TYPE: 'test'
            }}))

        # Switch 1 is ON, switch 2 is OFF
        self.switch_1, self.switch_2, self.switch_3 = \
            mock_toggledevice_platform.get_switches(None, None)
示例#16
0
def setUpModule():  # pylint: disable=invalid-name
    """ Initalizes a Home Assistant server. """
    global KNOWN_DEV_PATH

    hass = get_test_home_assistant()

    loader.prepare(hass)
    KNOWN_DEV_PATH = hass.config.path(device_tracker.KNOWN_DEVICES_FILE)

    hass.stop()

    with open(KNOWN_DEV_PATH, 'w') as fil:
        fil.write('device,name,track,picture\n')
        fil.write('DEV1,device 1,1,http://example.com/dev1.jpg\n')
        fil.write('DEV2,device 2,1,http://example.com/dev2.jpg\n')
def setUpModule():   # pylint: disable=invalid-name
    """ Initalizes a Home Assistant server. """
    global KNOWN_DEV_PATH

    hass = get_test_home_assistant()

    loader.prepare(hass)
    KNOWN_DEV_PATH = hass.config.path(
        device_tracker.KNOWN_DEVICES_FILE)

    hass.stop()

    with open(KNOWN_DEV_PATH, 'w') as fil:
        fil.write('device,name,track,picture\n')
        fil.write('DEV1,device 1,1,http://example.com/dev1.jpg\n')
        fil.write('DEV2,device 2,1,http://example.com/dev2.jpg\n')
示例#18
0
def from_config_dict(config, hass=None):
    """
    Tries to configure Home Assistant from a config dict.


    Dynamically loads required components and its dependencies.
    """

    # Make a copy because we are mutating it.
    # Convert it to defaultdict so components can always have config dict
    config = defaultdict(dict, config)

    if hass is None:
        hass = homeassistant.HomeAssistant(config)

    logger = logging.getLogger(__name__)

    loader.prepare(hass)


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

    # Setup the components
    if core_components.setup(hass, config):
        logger.info("Home Assistant core initialized")

        for domain in loader.load_order_components(components):
            if domain is not "pushbullet":
                try:
                    if loader.get_component(domain).setup(hass, config):
                        logger.info("component %s initialized", domain)
                    else:
                        logger.error("component %s failed to initialize", domain)

                except Exception:  # pylint: disable=broad-except
                    logger.exception("Error during setup of component %s", domain)

    else:
        logger.error(("Home Assistant core failed to initialize. "
                      "Further initialization aborted."))

    return hass
示例#19
0
def get_test_home_assistant(num_threads=None):
    """ Returns a Home Assistant object pointing at test config dir. """
    if num_threads:
        orig_num_threads = ha.MIN_WORKER_THREAD
        ha.MIN_WORKER_THREAD = num_threads

    hass = ha.HomeAssistant()

    if num_threads:
        ha.MIN_WORKER_THREAD = orig_num_threads

    hass.config.config_dir = get_test_config_dir()
    hass.config.latitude = 32.87336
    hass.config.longitude = -117.22743

    if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
        loader.prepare(hass)

    return hass
示例#20
0
def get_test_home_assistant(num_threads=None):
    """ Returns a Home Assistant object pointing at test config dir. """
    if num_threads:
        orig_num_threads = ha.MIN_WORKER_THREAD
        ha.MIN_WORKER_THREAD = num_threads

    hass = ha.HomeAssistant()

    if num_threads:
        ha.MIN_WORKER_THREAD = orig_num_threads

    hass.config.config_dir = get_test_config_dir()
    hass.config.latitude = 32.87336
    hass.config.longitude = -117.22743

    if "custom_components.test" not in loader.AVAILABLE_COMPONENTS:
        loader.prepare(hass)

    return hass
示例#21
0
def get_test_home_assistant(num_threads=None):
    """Return a Home Assistant object pointing at test config dir."""
    if num_threads:
        orig_num_threads = ha.MIN_WORKER_THREAD
        ha.MIN_WORKER_THREAD = num_threads

    hass = ha.HomeAssistant()

    if num_threads:
        ha.MIN_WORKER_THREAD = orig_num_threads

    hass.config.config_dir = get_test_config_dir()
    hass.config.latitude = 32.87336
    hass.config.longitude = -117.22743
    hass.config.time_zone = date_util.get_time_zone('US/Pacific')
    hass.config.temperature_unit = TEMP_CELSIUS

    if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
        loader.prepare(hass)

    return hass
示例#22
0
def get_test_home_assistant(num_threads=None):
    """Return a Home Assistant object pointing at test config dir."""
    if num_threads:
        orig_num_threads = ha.MIN_WORKER_THREAD
        ha.MIN_WORKER_THREAD = num_threads

    hass = ha.HomeAssistant()

    if num_threads:
        ha.MIN_WORKER_THREAD = orig_num_threads

    hass.config.config_dir = get_test_config_dir()
    hass.config.latitude = 32.87336
    hass.config.longitude = -117.22743
    hass.config.time_zone = date_util.get_time_zone('US/Pacific')
    hass.config.temperature_unit = TEMP_CELCIUS

    if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
        loader.prepare(hass)

    return hass
示例#23
0
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()

    logger = logging.getLogger(__name__)

    loader.prepare(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)

    # Setup the components
    if core_components.setup(hass, config):
        logger.info("Home Assistant core initialized")

        for domain in loader.load_order_components(components):
            try:
                if loader.get_component(domain).setup(hass, config):
                    logger.info("component %s initialized", domain)
                else:
                    logger.error("component %s failed to initialize", domain)

            except Exception:  # pylint: disable=broad-except
                logger.exception("Error during setup of component %s", domain)

    else:
        logger.error(("Home Assistant core failed to initialize. "
                      "Further initialization aborted."))

    return hass
示例#24
0
def _ensure_loader_prepared(hass):
    """ Ensure Home Assistant loader is prepared. """
    if not loader.PREPARED:
        loader.prepare(hass)
 def setUp(self):  # pylint: disable=invalid-name
     self.hass = get_test_home_assistant()
     loader.prepare(self.hass)
示例#26
0
def check(config_dir, secrets=False):
    """Perform a check by mocking hass load functions."""
    logging.getLogger('homeassistant.loader').setLevel(logging.CRITICAL)
    res = {
        'yaml_files': OrderedDict(),  # yaml_files loaded
        'secrets': OrderedDict(),  # secret cache and secrets loaded
        'except': OrderedDict(),  # exceptions raised (with config)
        'components': None,  # successful components
        'secret_cache': None,
    }

    # pylint: disable=unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config file names."""
        res['yaml_files'][filename] = True
        return MOCKS['load'][1](filename)

    # pylint: disable=unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS['secrets'][1](ldr, node)
        except HomeAssistantError:
            val = None
        res['secrets'][node.value] = val
        return val

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        if not secrets and key == 'secrets':
            continue
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()['mock_' + key.replace('*', '')]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()

    if secrets:
        # Ensure !secrets point to the patched function
        yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)

    try:
        class HassConfig():
            """Hass object with config."""

            def __init__(self, conf_dir):
                """Init the config_dir."""
                self.config = core.Config()
                self.config.config_dir = conf_dir

        loader.prepare(HassConfig(config_dir))

        res['components'] = check_ha_config_file(config_dir)

        res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE)

        for err in res['components'].errors:
            domain = err.domain or ERROR_STR
            res['except'].setdefault(domain, []).append(err.message)
            if err.config:
                res['except'].setdefault(domain, []).append(err.config)

    except Exception as err:  # pylint: disable=broad-except
        print(color('red', 'Fatal error while loading config:'), str(err))
        res['except'].setdefault(ERROR_STR, []).append(str(err))
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        if secrets:
            # Ensure !secrets point to the original function
            yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
        bootstrap.clear_secret_cache()

    return res
 def setUp(self):  # pylint: disable=invalid-name
     self.hass = get_test_home_assistant()
     loader.prepare(self.hass)
     loader.set_component('light.test', mock_toggledevice_platform)
示例#28
0
def _ensure_loader_prepared(hass):
    """ Ensure Home Assistant loader is prepared. """
    if not loader.PREPARED:
        loader.prepare(hass)
示例#29
0
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()

    logger = logging.getLogger(__name__)

    # Make a copy because we are mutating it.
    # Convert it to defaultdict so components can always have config dict
    config = defaultdict(dict, config)

    # List of loaded components
    components = {}

    # List of components to validate
    to_validate = []

    # List of validated components
    validated = []

    # List of components we are going to load
    to_load = [key for key in config.keys() if key != homeassistant.DOMAIN]

    loader.prepare(hass)

    # Load required components
    while to_load:
        domain = to_load.pop()

        component = loader.get_component(domain)

        # if None it does not exist, error already thrown by get_component
        if component is not None:
            components[domain] = component

            # Special treatment for GROUP, we want to load it as late as
            # possible. We do this by loading it if all other to be loaded
            # modules depend on it.
            if component.DOMAIN == group.DOMAIN:
                pass

            # Components with no dependencies are valid
            elif not component.DEPENDENCIES:
                validated.append(domain)

            # If dependencies we'll validate it later
            else:
                to_validate.append(domain)

                # Make sure to load all dependencies that are not being loaded
                for dependency in component.DEPENDENCIES:
                    if dependency not in chain(components.keys(), to_load):
                        to_load.append(dependency)

    # Validate dependencies
    group_added = False

    while to_validate:
        newly_validated = []

        for domain in to_validate:
            if all(domain in validated for domain
                   in components[domain].DEPENDENCIES):

                newly_validated.append(domain)

        # We validated new domains this iteration, add them to validated
        if newly_validated:

            # Add newly validated domains to validated
            validated.extend(newly_validated)

            # remove domains from to_validate
            for domain in newly_validated:
                to_validate.remove(domain)

            newly_validated.clear()

        # Nothing validated this iteration. Add group dependency and try again.
        elif not group_added:
            group_added = True
            validated.append(group.DOMAIN)

        # Group has already been added and we still can't validate all.
        # Report missing deps as error and skip loading of these domains
        else:
            for domain in to_validate:
                missing_deps = [dep for dep in components[domain].DEPENDENCIES
                                if dep not in validated]

                logger.error(
                    "Could not validate all dependencies for %s: %s",
                    domain, ", ".join(missing_deps))

            break

    # Make sure we load groups if not in list yet.
    if not group_added:
        validated.append(group.DOMAIN)

        if group.DOMAIN not in components:
            components[group.DOMAIN] = \
                loader.get_component(group.DOMAIN)

    # Setup the components
    if core_components.setup(hass, config):
        logger.info("Home Assistant core initialized")

        for domain in validated:
            component = components[domain]

            try:
                if component.setup(hass, config):
                    logger.info("component %s initialized", domain)
                else:
                    logger.error("component %s failed to initialize", domain)

            except Exception:  # pylint: disable=broad-except
                logger.exception("Error during setup of component %s", domain)

    else:
        logger.error(("Home Assistant core failed to initialize. "
                      "Further initialization aborted."))

    return hass
示例#30
0
def get_test_home_assistant(num_threads=None):
    """Return a Home Assistant object pointing at test config dir."""
    loop = asyncio.new_event_loop()

    if num_threads:
        orig_num_threads = ha.MIN_WORKER_THREAD
        ha.MIN_WORKER_THREAD = num_threads

    hass = ha.HomeAssistant(loop)

    if num_threads:
        ha.MIN_WORKER_THREAD = orig_num_threads

    hass.config.location_name = 'test home'
    hass.config.config_dir = get_test_config_dir()
    hass.config.latitude = 32.87336
    hass.config.longitude = -117.22743
    hass.config.elevation = 0
    hass.config.time_zone = date_util.get_time_zone('US/Pacific')
    hass.config.units = METRIC_SYSTEM
    hass.config.skip_pip = True

    if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
        loader.prepare(hass)

    # FIXME should not be a daemon. Means hass.stop() not called in teardown
    stop_event = threading.Event()

    def run_loop():
        loop.run_forever()
        loop.close()
        stop_event.set()

    threading.Thread(name="LoopThread", target=run_loop, daemon=True).start()

    orig_start = hass.start
    orig_stop = hass.stop

    @asyncio.coroutine
    def fake_stop():
        yield None

    def start_hass():
        """Helper to start hass."""
        with patch.object(hass.loop, 'run_forever', return_value=None):
            with patch.object(hass, 'async_stop', return_value=fake_stop()):
                with patch.object(ha, 'async_create_timer', return_value=None):
                    with patch.object(ha, 'async_monitor_worker_pool',
                                      return_value=None):
                        with patch.object(hass.loop, 'add_signal_handler'):
                            orig_start()
                            hass.block_till_done()

    def stop_hass():
        orig_stop()
        stop_event.wait()

    hass.start = start_hass
    hass.stop = stop_hass

    return hass
示例#31
0
 def setUp(self):  # pylint: disable=invalid-name
     self.hass = get_test_home_assistant()
     loader.prepare(self.hass)
示例#32
0
def check(config_dir, secrets=False):
    """Perform a check by mocking hass load functions."""
    logging.getLogger('homeassistant.loader').setLevel(logging.CRITICAL)
    res = {
        'yaml_files': OrderedDict(),  # yaml_files loaded
        'secrets': OrderedDict(),  # secret cache and secrets loaded
        'except': OrderedDict(),  # exceptions raised (with config)
        'components': None,  # successful components
        'secret_cache': None,
    }

    # pylint: disable=unused-variable
    def mock_load(filename):
        """Mock hass.util.load_yaml to save config file names."""
        res['yaml_files'][filename] = True
        return MOCKS['load'][1](filename)

    # pylint: disable=unused-variable
    def mock_secrets(ldr, node):
        """Mock _get_secrets."""
        try:
            val = MOCKS['secrets'][1](ldr, node)
        except HomeAssistantError:
            val = None
        res['secrets'][node.value] = val
        return val

    # Patches to skip functions
    for sil in SILENCE:
        PATCHES[sil] = patch(sil)

    # Patches with local mock functions
    for key, val in MOCKS.items():
        if not secrets and key == 'secrets':
            continue
        # The * in the key is removed to find the mock_function (side_effect)
        # This allows us to use one side_effect to patch multiple locations
        mock_function = locals()['mock_' + key.replace('*', '')]
        PATCHES[key] = patch(val[0], side_effect=mock_function)

    # Start all patches
    for pat in PATCHES.values():
        pat.start()

    if secrets:
        # Ensure !secrets point to the patched function
        yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)

    try:

        class HassConfig():
            """Hass object with config."""
            def __init__(self, conf_dir):
                """Init the config_dir."""
                self.config = core.Config()
                self.config.config_dir = conf_dir

        loader.prepare(HassConfig(config_dir))

        res['components'] = check_ha_config_file(config_dir)

        res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE)

        for err in res['components'].errors:
            domain = err.domain or ERROR_STR
            res['except'].setdefault(domain, []).append(err.message)
            if err.config:
                res['except'].setdefault(domain, []).append(err.config)

    except Exception as err:  # pylint: disable=broad-except
        print(color('red', 'Fatal error while loading config:'), str(err))
        res['except'].setdefault(ERROR_STR, []).append(str(err))
    finally:
        # Stop all patches
        for pat in PATCHES.values():
            pat.stop()
        if secrets:
            # Ensure !secrets point to the original function
            yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
        bootstrap.clear_secret_cache()

    return res