def _setup_component(hass, domain, config): """Setup a component for Home Assistant.""" # pylint: disable=too-many-return-statements,too-many-branches if domain in hass.config.components: return True with _SETUP_LOCK: # It might have been loaded while waiting for lock if domain in hass.config.components: return True if domain in _CURRENT_SETUP: _LOGGER.error('Attempt made to setup %s during setup of %s', domain, domain) return False component = loader.get_component(domain) missing_deps = [ dep for dep in getattr(component, 'DEPENDENCIES', []) if dep not in hass.config.components ] if missing_deps: _LOGGER.error( 'Not initializing %s because not all dependencies loaded: %s', domain, ", ".join(missing_deps)) return False if hasattr(component, 'CONFIG_SCHEMA'): try: config = component.CONFIG_SCHEMA(config) except vol.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, domain, config) return False elif hasattr(component, 'PLATFORM_SCHEMA'): 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.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, domain, p_config) return False # 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 = prepare_setup_platform(hass, config, domain, p_name) if platform is None: return False # Validate platform specific schema if hasattr(platform, 'PLATFORM_SCHEMA'): try: p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, '{}.{}'.format(domain, p_name), p_validated) return False platforms.append(p_validated) # Create a copy of the configuration with all config for current # component removed and add validated config back in. filter_keys = extract_domain_configs(config, domain) config = { key: value for key, value in config.items() if key not in filter_keys } config[domain] = platforms if not _handle_requirements(hass, component, domain): return False _CURRENT_SETUP.append(domain) try: if not component.setup(hass, config): _LOGGER.error('component %s failed to initialize', domain) return False except Exception: # pylint: disable=broad-except _LOGGER.exception('Error during setup of component %s', domain) return False finally: _CURRENT_SETUP.remove(domain) hass.config.components.append(component.DOMAIN) # Assumption: if a component does not depend on groups # it communicates with devices if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []): hass.pool.add_worker() hass.bus.fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN}) return True
def _setup_component(hass, domain, config): """Setup a component for Home Assistant.""" # pylint: disable=too-many-return-statements,too-many-branches if domain in hass.config.components: return True with _SETUP_LOCK: # It might have been loaded while waiting for lock if domain in hass.config.components: return True if domain in _CURRENT_SETUP: _LOGGER.error('Attempt made to setup %s during setup of %s', domain, domain) return False component = loader.get_component(domain) missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', []) if dep not in hass.config.components] if missing_deps: _LOGGER.error( 'Not initializing %s because not all dependencies loaded: %s', domain, ", ".join(missing_deps)) return False if hasattr(component, 'CONFIG_SCHEMA'): try: config = component.CONFIG_SCHEMA(config) except vol.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, domain, config) return False elif hasattr(component, 'PLATFORM_SCHEMA'): 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.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, domain, p_config) return False # 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 = prepare_setup_platform(hass, config, domain, p_name) if platform is None: return False # Validate platform specific schema if hasattr(platform, 'PLATFORM_SCHEMA'): try: p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, '{}.{}' .format(domain, p_name), p_validated) return False platforms.append(p_validated) # Create a copy of the configuration with all config for current # component removed and add validated config back in. filter_keys = extract_domain_configs(config, domain) config = {key: value for key, value in config.items() if key not in filter_keys} config[domain] = platforms if not _handle_requirements(hass, component, domain): return False _CURRENT_SETUP.append(domain) try: if not component.setup(hass, config): _LOGGER.error('component %s failed to initialize', domain) return False except Exception: # pylint: disable=broad-except _LOGGER.exception('Error during setup of component %s', domain) return False finally: _CURRENT_SETUP.remove(domain) hass.config.components.append(component.DOMAIN) # Assumption: if a component does not depend on groups # it communicates with devices if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []): hass.pool.add_worker() hass.bus.fire( EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN}) return True
def from_config_dict(config, hass=None, config_dir=None, enable_log=True, verbose=False, skip_pip=False, log_rotate_days=None): """Try to configure Home Assistant from a config dict. Dynamically loads required components and its dependencies. """ if hass is None: hass = core.HomeAssistant() 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) core_config = config.get(core.DOMAIN, {}) try: conf_util.process_ha_core_config(hass, core_config) except vol.Invalid as ex: cv.log_exception(_LOGGER, ex, 'homeassistant', core_config) return 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.') _ensure_loader_prepared(hass) # Make a copy because we are mutating it. # Convert it to defaultdict so components can always have config dict # Convert values to dictionaries if they are None config = defaultdict(dict, {key: value or {} for key, value in config.items()}) # Filter out the repeating and common config section [homeassistant] components = set( key.split(' ')[0] for key in config.keys() if key != core.DOMAIN) if not core_components.setup(hass, config): _LOGGER.error('Home Assistant core failed to initialize. ' 'Further initialization aborted.') return hass persistent_notification.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): _setup_component(hass, domain, config) return hass
def from_config_dict(config, hass=None, config_dir=None, enable_log=True, verbose=False, daemon=False, skip_pip=False, log_rotate_days=None): """Try to configure Home Assistant from a config dict. Dynamically loads required components and its dependencies. """ if hass is None: hass = core.HomeAssistant() 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) core_config = config.get(core.DOMAIN, {}) try: process_ha_core_config(hass, config_util.CORE_CONFIG_SCHEMA( core_config)) except vol.MultipleInvalid as ex: cv.log_exception(_LOGGER, ex, 'homeassistant', core_config) return None process_ha_config_upgrade(hass) if enable_log: enable_logging(hass, verbose, daemon, log_rotate_days) hass.config.skip_pip = skip_pip if skip_pip: _LOGGER.warning('Skipping pip installation of required modules. ' 'This may cause issues.') _ensure_loader_prepared(hass) # Make a copy because we are mutating it. # Convert it to defaultdict so components can always have config dict # Convert values to dictionaries if they are None config = defaultdict( dict, {key: value or {} for key, value in config.items()}) # Filter out the repeating and common config section [homeassistant] components = set(key.split(' ')[0] for key in config.keys() if key != core.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') # Give event decorators access to HASS event_decorators.HASS = hass service.HASS = hass # Setup the components for domain in loader.load_order_components(components): _setup_component(hass, domain, config) return hass