Esempio n. 1
0
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
Esempio n. 2
0
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))
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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
Esempio n. 8
0
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))
Esempio n. 10
0
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)
Esempio n. 11
0
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
Esempio n. 12
0
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)
Esempio n. 13
0
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)
Esempio n. 14
0
    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)
Esempio n. 15
0
    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)
Esempio n. 16
0
    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()
Esempio n. 17
0
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)
Esempio n. 18
0
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)
Esempio n. 19
0
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
Esempio n. 20
0
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
Esempio n. 21
0
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
Esempio n. 22
0
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
Esempio n. 23
0
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
Esempio n. 24
0
    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)
Esempio n. 25
0
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
Esempio n. 26
0
    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)
Esempio n. 27
0
    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)
Esempio n. 28
0
    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)
Esempio n. 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
Esempio n. 30
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)
    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
Esempio n. 31
0
    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)
Esempio n. 32
0
    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)