async def test_get_platform(hass, caplog): """Test get_platform.""" # Test we prefer embedded over normal platforms.""" embedded_platform = loader.get_platform(hass, 'switch', 'test_embedded') assert embedded_platform.__name__ == \ 'custom_components.test_embedded.switch' caplog.clear() legacy_platform = loader.get_platform(hass, 'switch', 'test') assert legacy_platform.__name__ == 'custom_components.switch.test' assert 'Integrations need to be in their own folder.' in caplog.text
async def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. This method is a coroutine. """ platform_path = PLATFORM_FORMAT.format(domain, platform_name) def log_error(msg): """Log helper.""" _LOGGER.error("Unable to prepare setup for platform %s: %s", platform_path, msg) async_notify_setup_error(hass, platform_path) platform = loader.get_platform(hass, domain, platform_name) # Not found if platform is None: log_error("Platform not found.") return None # Already loaded elif platform_path in hass.config.components: return platform try: await async_process_deps_reqs(hass, config, platform_path, platform) except HomeAssistantError as err: log_error(str(err)) return None return platform
def validator(value): """Test if platform exists.""" if value is None: raise vol.Invalid("platform cannot be None") if get_platform(domain, str(value)): return value raise vol.Invalid("platform {} does not exist for {}".format(value, domain))
def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. This method is a coroutine. """ platform_path = PLATFORM_FORMAT.format(domain, platform_name) def log_error(msg): """Log helper.""" _LOGGER.error("Unable to prepare setup for platform %s: %s", platform_path, msg) async_notify_setup_error(hass, platform_path) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: log_error("Platform not found.") return None # Already loaded elif platform_path in hass.config.components: return platform try: yield from async_process_deps_reqs( hass, config, platform_path, platform) except HomeAssistantError as err: log_error(str(err)) return None return platform
def prepare_setup_platform(hass, config, domain, platform_name): """Load a platform and makes sure dependencies are setup.""" _ensure_loader_prepared(hass) platform_path = PLATFORM_FORMAT.format(domain, platform_name) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: _LOGGER.error('Unable to find platform %s', platform_path) return None # Already loaded elif platform_path in hass.config.components: return platform # Load dependencies for component in getattr(platform, 'DEPENDENCIES', []): if not setup_component(hass, component, config): _LOGGER.error( 'Unable to prepare setup for platform %s because ' 'dependency %s could not be initialized', platform_path, component) return None if not _handle_requirements(hass, platform, platform_path): return None return platform
def async_process_component_config(hass, config, domain): """Check component config and return processed config. Raise a vol.Invalid exception on error. This method must be run in the event loop. """ component = get_component(domain) if hasattr(component, 'CONFIG_SCHEMA'): try: config = component.CONFIG_SCHEMA(config) except vol.Invalid as ex: async_log_exception(ex, domain, config, hass) return None 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.Invalid as ex: async_log_exception(ex, domain, config, hass) 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 = get_platform(domain, p_name) if platform is None: continue # Validate platform specific schema if hasattr(platform, 'PLATFORM_SCHEMA'): # pylint: disable=no-member try: p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.Invalid as ex: async_log_exception(ex, '{}.{}'.format(domain, p_name), p_validated, hass) continue 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 return config
def _platform_validator(config): """Validate it is a valid platform.""" platform = get_platform(DOMAIN, config[CONF_PLATFORM]) if not hasattr(platform, 'TRIGGER_SCHEMA'): return config return getattr(platform, 'TRIGGER_SCHEMA')(config)
def validator(value): """Test if platform exists.""" if value is None: raise vol.Invalid('platform cannot be None') if get_platform(domain, str(value)): return value raise vol.Invalid('platform {} does not exist for {}'.format( value, domain))
def async_process_component_config(hass, config, domain): """Check component configuration and return processed configuration. Returns None on error. This method must be run in the event loop. """ component = get_component(hass, domain) if hasattr(component, 'CONFIG_SCHEMA'): try: config = component.CONFIG_SCHEMA(config) except vol.Invalid as ex: async_log_exception(ex, domain, config, hass) return None 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.Invalid as ex: async_log_exception(ex, domain, config, hass) 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 = get_platform(hass, domain, p_name) if platform is None: continue # Validate platform specific schema if hasattr(platform, 'PLATFORM_SCHEMA'): # pylint: disable=no-member try: p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.Invalid as ex: async_log_exception(ex, '{}.{}'.format(domain, p_name), p_validated, hass) continue 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 return config
def _platform_validator(config): """Validate it is a valid platform.""" p_name = config[CONF_PLATFORM] platform = get_platform(DOMAIN, p_name) if not hasattr(platform, 'PLATFORM_SCHEMA'): return config return getattr(platform, 'PLATFORM_SCHEMA')(config)
def validator(config): """Validate it is a valid platform.""" platform = get_platform(DOMAIN, config[CONF_PLATFORM]) if not hasattr(platform, method): raise vol.Invalid('invalid method platform') if not hasattr(platform, schema): return config return getattr(platform, schema)(config)
def refresh_devices(event_time): _LOGGER.debug("Attempting to update Miele devices") device_state = client.get_devices(lang) if device_state is None: _LOGGER.error("Did not receive Miele devices") else: hass.data[DOMAIN][DATA_DEVICES] = _to_dict(device_state) for device in DEVICES: device.async_schedule_update_ha_state(True) for component in MIELE_COMPONENTS: platform = get_platform(hass, component, DOMAIN) platform.update_device_state()
def component_translation_file(hass: HomeAssistantType, component: str, language: str) -> str: """Return the translation json file location for a component. For component one of: - components/light/.translations/nl.json - components/.translations/group.nl.json For platform one of: - components/light/.translations/hue.nl.json - components/hue/.translations/light.nl.json """ is_platform = '.' in component if not is_platform: module = get_component(hass, component) assert module is not None module_path = pathlib.Path(module.__file__) if module.__name__ == module.__package__: # light/__init__.py filename = '{}.json'.format(language) else: # group.py filename = '{}.{}.json'.format(component, language) return str(module_path.parent / '.translations' / filename) # It's a platform parts = component.split('.', 1) module = get_platform(hass, *parts) assert module is not None, component # Either within HA or custom_components # Either light/hue.py or hue/light.py module_path = pathlib.Path(module.__file__) # Compare to parent so we don't have to strip off `.py` if module_path.parent.name == parts[0]: # this is light/hue.py filename = "{}.{}.json".format(parts[1], language) else: # this is hue/light.py filename = "{}.{}.json".format(parts[0], language) return str(module_path.parent / '.translations' / filename)
def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. This method is a coroutine. """ if not loader.PREPARED: yield from hass.loop.run_in_executor(None, loader.prepare, hass) platform_path = PLATFORM_FORMAT.format(domain, platform_name) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: _LOGGER.error('Unable to find platform %s', platform_path) _async_persistent_notification(hass, platform_path) return None # Already loaded elif platform_path in hass.config.components: return platform # Load dependencies for component in getattr(platform, 'DEPENDENCIES', []): if component in loader.DEPENDENCY_BLACKLIST: raise HomeAssistantError( '{} is not allowed to be a dependency.'.format(component)) res = yield from async_setup_component(hass, component, config) if not res: _LOGGER.error( 'Unable to prepare setup for platform %s because ' 'dependency %s could not be initialized', platform_path, component) _async_persistent_notification(hass, platform_path, True) return None res = yield from hass.loop.run_in_executor( None, _handle_requirements, hass, platform, platform_path) if not res: return None return platform
def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. This method is a coroutine. """ platform_path = PLATFORM_FORMAT.format(domain, platform_name) def log_error(msg): """Log helper.""" _LOGGER.error('Unable to prepare setup for platform %s: %s', platform_path, msg) async_notify_setup_error(hass, platform_path) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: log_error('Platform not found.') return None # Already loaded elif platform_path in hass.config.components: return platform # Load dependencies if hasattr(platform, 'DEPENDENCIES'): dep_success = yield from _async_process_dependencies( hass, config, platform_path, platform.DEPENDENCIES) if not dep_success: log_error('Could not setup all dependencies.') return None if not hass.config.skip_pip and hasattr(platform, 'REQUIREMENTS'): req_success = yield from _async_process_requirements( hass, platform_path, platform.REQUIREMENTS) if not req_success: log_error('Could not install all requirements.') return None return platform
def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. This method is a coroutine. """ platform_path = PLATFORM_FORMAT.format(domain, platform_name) def log_error(msg): """Log helper.""" _LOGGER.error("Unable to prepare setup for platform %s: %s", platform_path, msg) async_notify_setup_error(hass, platform_path) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: log_error("Platform not found.") return None # Already loaded elif platform_path in hass.config.components: return platform # Load dependencies if hasattr(platform, 'DEPENDENCIES'): dep_success = yield from _async_process_dependencies( hass, config, platform_path, platform.DEPENDENCIES) if not dep_success: log_error("Could not setup all dependencies.") return None if not hass.config.skip_pip and hasattr(platform, 'REQUIREMENTS'): req_success = yield from _async_process_requirements( hass, platform_path, platform.REQUIREMENTS) if not req_success: log_error("Could not install all requirements.") return None return platform
def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup.""" _ensure_loader_prepared(hass) platform_path = PLATFORM_FORMAT.format(domain, platform_name) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: _LOGGER.error("Unable to find platform %s", platform_path) _PERSISTENT_PLATFORMS.add(platform_path) message = ( "Unable to find the following platforms: " + ", ".join(list(_PERSISTENT_PLATFORMS)) + "(please check your configuration)" ) persistent_notification.create(hass, message, "Invalid platforms", "platform_errors") return None # Already loaded elif platform_path in hass.config.components: return platform # Load dependencies for component in getattr(platform, "DEPENDENCIES", []): if not setup_component(hass, component, config): _LOGGER.error( "Unable to prepare setup for platform %s because " "dependency %s could not be initialized", platform_path, component, ) return None if not _handle_requirements(hass, platform, platform_path): return None return platform
def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, platform_name: str) -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup.""" _ensure_loader_prepared(hass) platform_path = PLATFORM_FORMAT.format(domain, platform_name) platform = loader.get_platform(domain, platform_name) # Not found if platform is None: _LOGGER.error('Unable to find platform %s', platform_path) _PERSISTENT_PLATFORMS.add(platform_path) message = ('Unable to find the following platforms: ' + ', '.join(list(_PERSISTENT_PLATFORMS)) + '(please check your configuration)') persistent_notification.create(hass, message, 'Invalid platforms', 'platform_errors') return None # Already loaded elif platform_path in hass.config.components: return platform # Load dependencies for component in getattr(platform, 'DEPENDENCIES', []): if not setup_component(hass, component, config): _LOGGER.error( 'Unable to prepare setup for platform %s because ' 'dependency %s could not be initialized', platform_path, component) return None if not _handle_requirements(hass, platform, platform_path): return None return platform
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and \ not self._schema[const.DISC_VALUES][name].get( const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component value_name = _value_name(self.primary) if self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]: generated_id = generate_entity_id(component + '.{}', value_name, []) else: generated_id = "{}.{}".format(component, object_id(self.primary)) node_config = self._device_config.get(generated_id) # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring entity %s due to device settings", generated_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert(node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) platform = get_platform(component, DOMAIN) device = platform.get_device(node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return device.old_entity_id = "{}.{}".format(component, object_id(self.primary)) device.new_entity_id = "{}.{}".format(component, slugify(device.name)) if not self._zwave_config[DOMAIN][CONF_NEW_ENTITY_IDS]: device.entity_id = device.old_entity_id self._entity = device dict_id = id(self) @asyncio.coroutine def discover_device(component, device, dict_id): """Put device in a dictionary and call discovery on it.""" self._hass.data[DATA_DEVICES][dict_id] = device yield from discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: dict_id}, self._zwave_config) self._hass.add_job(discover_device, component, device, dict_id)
async def test_get_platform_enforces_component_path(hass, caplog): """Test that existence of a component limits lookup path of platforms.""" assert loader.get_platform(hass, 'comp_path_test', 'hue') is None assert ('Search path was limited to path of component: ' 'homeassistant.components') in caplog.text
def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug("node.generic %s not None and in " "generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug("node.specific %s is not None and in " "specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug("value.command_class %s is not None " "and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre, component) workaround_component = workaround.get_device_component_mapping( value) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring device %s due to workaround.", "{}.{}".format(component, object_id(value))) continue _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component name = "{}.{}".format(component, object_id(value)) node_config = device_config.get(name) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring device %s due to device settings.", name) return polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() platform = get_platform(component, DOMAIN) device = platform.get_device( node=node, value=value, node_config=node_config, hass=hass) if not device: continue dict_id = "{}.{}".format(component, value.value_id) @asyncio.coroutine def discover_device(component, device, dict_id): """Put device in a dictionary and call discovery on it.""" hass.data[DATA_ZWAVE_DICT][dict_id] = device yield from discovery.async_load_platform( hass, component, DOMAIN, {const.DISCOVERY_DEVICE: dict_id}, config) hass.add_job(discover_device, component, device, dict_id)
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and \ not self._schema[const.DISC_VALUES][name].get( const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component entity_id = self._registry.async_get_entity_id( component, DOMAIN, compute_value_unique_id(self._node, self.primary)) if entity_id is None: value_name = _value_name(self.primary) entity_id = generate_entity_id(component + '.{}', value_name, []) node_config = self._device_config.get(entity_id) # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring entity %s due to device settings", entity_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) platform = get_platform(self._hass, component, DOMAIN) device = platform.get_device( node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return self._entity = device @callback def _on_ready(sec): _LOGGER.info( "Z-Wave entity %s (node_id: %d) ready after %d seconds", device.name, self._node.node_id, sec) self._hass.async_add_job(discover_device, component, device) @callback def _on_timeout(sec): _LOGGER.warning( "Z-Wave entity %s (node_id: %d) not ready after %d seconds, " "continuing anyway", device.name, self._node.node_id, sec) self._hass.async_add_job(discover_device, component, device) async def discover_device(component, device): """Put device in a dictionary and call discovery on it.""" if self._hass.data[DATA_DEVICES].get(device.unique_id): return self._hass.data[DATA_DEVICES][device.unique_id] = device if component in SUPPORTED_PLATFORMS: async_dispatcher_send( self._hass, 'zwave_new_{}'.format(component), device) else: await discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: device.unique_id}, self._zwave_config) if device.unique_id: self._hass.add_job(discover_device, component, device) else: self._hass.add_job(check_has_unique_id, device, _on_ready, _on_timeout, self._hass.loop)
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and \ not self._schema[const.DISC_VALUES][name].get( const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring Node %d Value %d due to workaround.", self.primary.node.node_id, self.primary.value_id) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component entity_id = self._registry.async_get_entity_id( component, DOMAIN, compute_value_unique_id(self._node, self.primary)) if entity_id is None: value_name = _value_name(self.primary) entity_id = generate_entity_id(component + '.{}', value_name, []) node_config = self._device_config.get(entity_id) # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring entity %s due to device settings", entity_id) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert(node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) platform = get_platform(self._hass, component, DOMAIN) device = platform.get_device(node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return self._entity = device @callback def _on_ready(sec): _LOGGER.info( "Z-Wave entity %s (node_id: %d) ready after %d seconds", device.name, self._node.node_id, sec) self._hass.async_add_job(discover_device, component, device) @callback def _on_timeout(sec): _LOGGER.warning( "Z-Wave entity %s (node_id: %d) not ready after %d seconds, " "continuing anyway", device.name, self._node.node_id, sec) self._hass.async_add_job(discover_device, component, device) async def discover_device(component, device): """Put device in a dictionary and call discovery on it.""" if self._hass.data[DATA_DEVICES].get(device.unique_id): return self._hass.data[DATA_DEVICES][device.unique_id] = device if component in SUPPORTED_PLATFORMS: async_dispatcher_send(self._hass, 'zwave_new_{}'.format(component), device) else: await discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: device.unique_id}, self._zwave_config) if device.unique_id: self._hass.add_job(discover_device, component, device) else: self._hass.add_job(check_has_unique_id, device, _on_ready, _on_timeout, self._hass.loop)
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
def _check_entity_ready(self): """Check if all required values are discovered and create entity.""" if self._workaround_ignore: return if self._entity is not None: return for name in self._schema[const.DISC_VALUES]: if self._values[name] is None and \ not self._schema[const.DISC_VALUES][name].get( const.DISC_OPTIONAL): return component = self._schema[const.DISC_COMPONENT] workaround_component = workaround.get_device_component_mapping( self.primary) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring device %s due to workaround.", "{}.{}".format( component, object_id(self.primary))) # No entity will be created for this value self._workaround_ignore = True return _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component name = "{}.{}".format(component, object_id(self.primary)) node_config = self._device_config.get(name) # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", self._node.node_id, self._node.generic, self._node.specific, self.primary.command_class, self.primary.type, self.primary.genre, component) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring entity %s due to device settings", name) # No entity will be created for this value self._workaround_ignore = True return polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: self.primary.enable_poll(polling_intensity) else: self.primary.disable_poll() platform = get_platform(component, DOMAIN) device = platform.get_device( node=self._node, values=self, node_config=node_config, hass=self._hass) if device is None: # No entity will be created for this value self._workaround_ignore = True return self._entity = device dict_id = id(self) @asyncio.coroutine def discover_device(component, device, dict_id): """Put device in a dictionary and call discovery on it.""" self._hass.data[DATA_DEVICES][dict_id] = device yield from discovery.async_load_platform( self._hass, component, DOMAIN, {const.DISCOVERY_DEVICE: dict_id}, self._zwave_config) self._hass.add_job(discover_device, component, device, dict_id)
def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug( "node.generic %s not None and in " "generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug( "node.specific %s is not None and in " "specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug( "value.command_class %s is not None " "and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre, component) workaround_component = workaround.get_device_component_mapping( value) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring device %s due to workaround.", "{}.{}".format(component, object_id(value))) continue _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component name = "{}.{}".format(component, object_id(value)) node_config = device_config.get(name) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring device %s due to device settings.", name) return polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() platform = get_platform(component, DOMAIN) device = platform.get_device(node=node, value=value, node_config=node_config, hass=hass) if not device: continue dict_id = value.value_id @asyncio.coroutine def discover_device(component, device, dict_id): """Put device in a dictionary and call discovery on it.""" hass.data[DATA_ZWAVE_DICT][dict_id] = device yield from discovery.async_load_platform( hass, component, DOMAIN, {const.DISCOVERY_DEVICE: dict_id}, config) hass.add_job(discover_device, component, device, dict_id)