Example #1
0
def setup(hass, config):
    """ Setup zone. """
    entities = set()

    for key in extract_domain_configs(config, DOMAIN):
        entries = config[key]
        if not isinstance(entries, list):
            entries = entries,

        for entry in entries:
            name = entry.get(CONF_NAME, DEFAULT_NAME)
            latitude = entry.get(ATTR_LATITUDE)
            longitude = entry.get(ATTR_LONGITUDE)
            radius = entry.get(ATTR_RADIUS, DEFAULT_RADIUS)
            icon = entry.get(ATTR_ICON)

            if None in (latitude, longitude):
                logging.getLogger(__name__).error(
                    'Each zone needs a latitude and longitude.')
                continue

            zone = Zone(hass, name, latitude, longitude, radius, icon)
            zone.entity_id = generate_entity_id(ENTITY_ID_FORMAT, name,
                                                entities)
            zone.update_ha_state()
            entities.add(zone.entity_id)

    if ENTITY_ID_HOME not in entities:
        zone = Zone(hass, hass.config.location_name, hass.config.latitude,
                    hass.config.longitude, DEFAULT_RADIUS, ICON_HOME)
        zone.entity_id = ENTITY_ID_HOME
        zone.update_ha_state()

    return True
Example #2
0
def setup(hass, config):
    """Setup scenes."""
    logger = logging.getLogger(__name__)

    # You are not allowed to mutate the original config so make a copy
    config = dict(config)

    for config_key in extract_domain_configs(config, DOMAIN):
        platform_config = config[config_key]
        if not isinstance(platform_config, list):
            platform_config = [platform_config]

        if not any(CONF_PLATFORM in entry for entry in platform_config):
            platform_config = [{'platform': 'homeassistant', 'states': entry}
                               for entry in platform_config]

        config[config_key] = platform_config

    component = EntityComponent(logger, DOMAIN, hass)

    component.setup(config)

    def handle_scene_service(service):
        """Handle calls to the switch services."""
        target_scenes = component.extract_from_service(service)

        for scene in target_scenes:
            scene.activate()

    hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_scene_service,
                           schema=SCENE_SERVICE_SCHEMA)

    return True
Example #3
0
def _process_config(hass, config, component):
    """Process config and add automations."""
    success = False

    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            name = config_block.get(CONF_ALIAS) or "{} {}".format(config_key,
                                                                  list_no)

            hidden = config_block[CONF_HIDE_ENTITY]

            action = _get_action(hass, config_block.get(CONF_ACTION, {}), name)

            if CONF_CONDITION in config_block:
                cond_func = _process_if(hass, config, config_block)

                if cond_func is None:
                    continue
            else:
                def cond_func(variables):
                    """Condition will always pass."""
                    return True

            attach_triggers = partial(_process_trigger, hass, config,
                                      config_block.get(CONF_TRIGGER, []), name)
            entity = AutomationEntity(name, attach_triggers, cond_func, action,
                                      hidden)
            component.add_entities((entity,))
            success = True

    return success
Example #4
0
def prepare_setup_component(hass: core.HomeAssistant, config: dict, domain: str):
    """Prepare setup of a component and return processed config."""
    # pylint: disable=too-many-return-statements
    component = loader.get_component(domain)
    missing_deps = [dep for dep in getattr(component, "DEPENDENCIES", []) if dep not in hass.config.components]

    if missing_deps:
        _LOGGER.error("Not initializing %s because not all dependencies loaded: %s", domain, ", ".join(missing_deps))
        return None

    if hasattr(component, "CONFIG_SCHEMA"):
        try:
            config = component.CONFIG_SCHEMA(config)
        except vol.Invalid as ex:
            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:
                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 = prepare_setup_platform(hass, config, domain, p_name)

            if platform is None:
                continue

            # Validate platform specific schema
            if hasattr(platform, "PLATFORM_SCHEMA"):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    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

    if not _handle_requirements(hass, component, domain):
        return None

    return config
Example #5
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
Example #6
0
    def test_extract_domain_configs(self):
        config = {
            'zone': None,
            'zoner': None,
            'zone ': None,
            'zone Hallo': None,
            'zone 100': None,
        }

        self.assertEqual(set(['zone', 'zone Hallo', 'zone 100']),
                         set(helpers.extract_domain_configs(config, 'zone')))
Example #7
0
def setup(hass, config):
    """Setup the automation."""
    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            name = config_block.get(CONF_ALIAS, "{}, {}".format(config_key,
                                                                list_no))
            _setup_automation(hass, config_block, name, config)

    return True
Example #8
0
    def test_extract_domain_configs(self):
        """Test the extraction of domain configuration."""
        config = {
            'zone': None,
            'zoner': None,
            'zone ': None,
            'zone Hallo': None,
            'zone 100': None,
        }

        self.assertEqual(set(['zone', 'zone Hallo', 'zone 100']),
                         set(helpers.extract_domain_configs(config, 'zone')))
Example #9
0
def test_extract_domain_configs():
    """Test the extraction of domain configuration."""
    config = {
        'zone': None,
        'zoner': None,
        'zone ': None,
        'zone Hallo': None,
        'zone 100': None,
    }

    assert set(['zone', 'zone Hallo', 'zone 100']) == \
        set(helpers.extract_domain_configs(config, 'zone'))
Example #10
0
def test_extract_domain_configs():
    """Test the extraction of domain configuration."""
    config = {
        "zone": None,
        "zoner": None,
        "zone ": None,
        "zone Hallo": None,
        "zone 100": None,
    }

    assert set(["zone", "zone Hallo", "zone 100"
                ]) == set(helpers.extract_domain_configs(config, "zone"))
Example #11
0
    def test_extract_domain_configs(self):
        """Test the extraction of domain configuration."""
        config = {
            'zone': None,
            'zoner': None,
            'zone ': None,
            'zone Hallo': None,
            'zone 100': None,
        }

        self.assertEqual(set(['zone', 'zone Hallo', 'zone 100']),
                         set(helpers.extract_domain_configs(config, 'zone')))
Example #12
0
async def _async_process_config(hass, config, component):
    """Process config and add automations.

    This method is a coroutine.
    """
    entities = []

    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            automation_id = config_block.get(CONF_ID)
            name = config_block.get(CONF_ALIAS) or f"{config_key} {list_no}"

            hidden = config_block[CONF_HIDE_ENTITY]
            initial_state = config_block.get(CONF_INITIAL_STATE)

            action = _async_get_action(hass, config_block.get(CONF_ACTION, {}),
                                       name)

            if CONF_CONDITION in config_block:
                cond_func = await _async_process_if(hass, config, config_block)

                if cond_func is None:
                    continue
            else:

                def cond_func(variables):
                    """Condition will always pass."""
                    return True

            async_attach_triggers = partial(
                _async_process_trigger,
                hass,
                config,
                config_block.get(CONF_TRIGGER, []),
                name,
            )
            entity = AutomationEntity(
                automation_id,
                name,
                async_attach_triggers,
                cond_func,
                action,
                hidden,
                initial_state,
            )

            entities.append(entity)

    if entities:
        await component.async_add_entities(entities)
Example #13
0
def setup(hass, config):
    """Setup the automation."""
    success = False
    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            name = config_block.get(CONF_ALIAS,
                                    "{}, {}".format(config_key, list_no))
            success = (_setup_automation(hass, config_block, name, config)
                       or success)

    return success
Example #14
0
def setup(hass, config):
    """Setup the automation."""
    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        if not isinstance(conf, list):
            conf = [conf]

        for list_no, config_block in enumerate(conf):
            name = config_block.get(CONF_ALIAS,
                                    "{}, {}".format(config_key, list_no))
            _setup_automation(hass, config_block, name, config)

    return True
Example #15
0
def _async_process_config(hass, config, component):
    """Process config and add automations.

    This method is a coroutine.
    """
    entities = []
    tasks = []

    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            name = config_block.get(CONF_ALIAS) or "{} {}".format(
                config_key, list_no)

            hidden = config_block[CONF_HIDE_ENTITY]

            action = _async_get_action(hass, config_block.get(CONF_ACTION, {}),
                                       name)

            if CONF_CONDITION in config_block:
                cond_func = _async_process_if(hass, config, config_block)

                if cond_func is None:
                    continue
            else:

                def cond_func(variables):
                    """Condition will always pass."""
                    return True

            async_attach_triggers = partial(_async_process_trigger, hass,
                                            config,
                                            config_block.get(CONF_TRIGGER,
                                                             []), name)
            entity = AutomationEntity(name, async_attach_triggers, cond_func,
                                      action, hidden)
            if config_block[CONF_INITIAL_STATE]:
                tasks.append(entity.async_enable())
            entities.append(entity)

    if tasks:
        yield from asyncio.wait(tasks, loop=hass.loop)
    if entities:
        yield from component.async_add_entities(entities)

    return len(entities) > 0
Example #16
0
async def _async_process_config(hass, config, component):
    """Process config and add automations.

    This method is a coroutine.
    """
    entities = []

    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            automation_id = config_block.get(CONF_ID)
            name = config_block.get(CONF_ALIAS) or f"{config_key} {list_no}"

            initial_state = config_block.get(CONF_INITIAL_STATE)

            action_script = Script(
                hass,
                config_block[CONF_ACTION],
                name,
                script_mode=config_block[CONF_MODE],
                max_runs=config_block[CONF_MAX],
                logger=_LOGGER,
            )

            if CONF_CONDITION in config_block:
                cond_func = await _async_process_if(hass, config, config_block)

                if cond_func is None:
                    continue
            else:
                cond_func = None

            entity = AutomationEntity(
                automation_id,
                name,
                config_block[CONF_TRIGGER],
                cond_func,
                action_script,
                initial_state,
            )

            entities.append(entity)

    if entities:
        await component.async_add_entities(entities)
Example #17
0
def _async_process_config(hass, config, component):
    """Process config and add automations.

    This method is a coroutine.
    """
    entities = []
    tasks = []

    for config_key in extract_domain_configs(config, DOMAIN):
        conf = config[config_key]

        for list_no, config_block in enumerate(conf):
            name = config_block.get(CONF_ALIAS) or "{} {}".format(config_key,
                                                                  list_no)

            hidden = config_block[CONF_HIDE_ENTITY]

            action = _async_get_action(hass, config_block.get(CONF_ACTION, {}),
                                       name)

            if CONF_CONDITION in config_block:
                cond_func = _async_process_if(hass, config, config_block)

                if cond_func is None:
                    continue
            else:
                def cond_func(variables):
                    """Condition will always pass."""
                    return True

            async_attach_triggers = partial(
                _async_process_trigger, hass, config,
                config_block.get(CONF_TRIGGER, []), name)
            entity = AutomationEntity(name, async_attach_triggers, cond_func,
                                      action, hidden)
            if config_block[CONF_INITIAL_STATE]:
                tasks.append(entity.async_enable())
            entities.append(entity)

    if tasks:
        yield from asyncio.wait(tasks, loop=hass.loop)
    if entities:
        yield from component.async_add_entities(entities)

    return len(entities) > 0
def setup(hass, config):
    """Setup the ."""
    def _resume_mp(config):
        media_player = "media_player." + config.get("media_player", "")
        resume_state = None
        resume = False

        def _state_change(entity_id=None, old_state=None, new_state=None):
            nonlocal resume_state, resume
            content_id = hass.states.get(media_player).attributes.get(
                "media_content_id", [])
            if resume_state and new_state.state != 'playing' and resume:
                print(resume_state)
                data = {
                    ATTR_MEDIA_CONTENT_ID:
                    resume_state.attributes.get("media_content_id", ""),
                    ATTR_MEDIA_CONTENT_TYPE:
                    "audio/mp3",
                    ATTR_ENTITY_ID:
                    media_player,
                }
                resume_state = None
                resume = True
                hass.services.call(DOMAIN_MP, SERVICE_PLAY_MEDIA, data)
            elif (new_state.state == 'playing'
                  and ("nrk.no" in content_id
                       or "nrk-mms-live.online.no" in content_id)):
                resume_state = new_state
            elif (resume_state and new_state.state == 'playing'
                  and "tts_proxy" in content_id):
                resume = True
            else:
                resume_state = None
                resume = False

        track_state_change(hass, media_player, _state_change)

    for config_key in extract_domain_configs(config, DOMAIN):
        _resume_mp(config[config_key])
    return True
Example #19
0
def async_setup(hass, config):
    """Setup scenes."""
    logger = logging.getLogger(__name__)

    # You are not allowed to mutate the original config so make a copy
    config = dict(config)

    for config_key in extract_domain_configs(config, DOMAIN):
        platform_config = config[config_key]
        if not isinstance(platform_config, list):
            platform_config = [platform_config]

        if not any(CONF_PLATFORM in entry for entry in platform_config):
            platform_config = [{
                'platform': 'homeassistant',
                'states': entry
            } for entry in platform_config]

        config[config_key] = platform_config

    component = EntityComponent(logger, DOMAIN, hass)

    yield from component.async_setup(config)

    @asyncio.coroutine
    def async_handle_scene_service(service):
        """Handle calls to the switch services."""
        target_scenes = component.async_extract_from_service(service)

        tasks = [scene.async_activate() for scene in target_scenes]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TURN_ON,
                                 async_handle_scene_service,
                                 schema=SCENE_SERVICE_SCHEMA)

    return True
Example #20
0
async def _async_process_config(
    hass: HomeAssistant,
    config: dict[str, Any],
    component: EntityComponent,
) -> bool:
    """Process config and add automations.

    Returns if blueprints were used.
    """
    entities = []
    blueprints_used = False

    for config_key in extract_domain_configs(config, DOMAIN):
        conf: list[dict[str, Any] | blueprint.BlueprintInputs] = config[config_key]

        for list_no, config_block in enumerate(conf):
            raw_blueprint_inputs = None
            raw_config = None
            if isinstance(config_block, blueprint.BlueprintInputs):
                blueprints_used = True
                blueprint_inputs = config_block
                raw_blueprint_inputs = blueprint_inputs.config_with_inputs

                try:
                    raw_config = blueprint_inputs.async_substitute()
                    config_block = cast(
                        Dict[str, Any],
                        await async_validate_config_item(hass, raw_config),
                    )
                except vol.Invalid as err:
                    LOGGER.error(
                        "Blueprint %s generated invalid automation with inputs %s: %s",
                        blueprint_inputs.blueprint.name,
                        blueprint_inputs.inputs,
                        humanize_error(config_block, err),
                    )
                    continue
            else:
                raw_config = cast(AutomationConfig, config_block).raw_config

            automation_id = config_block.get(CONF_ID)
            name = config_block.get(CONF_ALIAS) or f"{config_key} {list_no}"

            initial_state = config_block.get(CONF_INITIAL_STATE)

            action_script = Script(
                hass,
                config_block[CONF_ACTION],
                name,
                DOMAIN,
                running_description="automation actions",
                script_mode=config_block[CONF_MODE],
                max_runs=config_block[CONF_MAX],
                max_exceeded=config_block[CONF_MAX_EXCEEDED],
                logger=LOGGER,
                # We don't pass variables here
                # Automation will already render them to use them in the condition
                # and so will pass them on to the script.
            )

            if CONF_CONDITION in config_block:
                cond_func = await _async_process_if(hass, name, config, config_block)

                if cond_func is None:
                    continue
            else:
                cond_func = None

            # Add trigger variables to variables
            variables = None
            if CONF_TRIGGER_VARIABLES in config_block:
                variables = ScriptVariables(
                    dict(config_block[CONF_TRIGGER_VARIABLES].as_dict())
                )
            if CONF_VARIABLES in config_block:
                if variables:
                    variables.variables.update(config_block[CONF_VARIABLES].as_dict())
                else:
                    variables = config_block[CONF_VARIABLES]

            entity = AutomationEntity(
                automation_id,
                name,
                config_block[CONF_TRIGGER],
                cond_func,
                action_script,
                initial_state,
                variables,
                config_block.get(CONF_TRIGGER_VARIABLES),
                raw_config,
                raw_blueprint_inputs,
                config_block[CONF_TRACE],
            )

            entities.append(entity)

    if entities:
        await component.async_add_entities(entities)

    return blueprints_used
Example #21
0
def async_process_component_config(hass: HomeAssistant, config: Dict,
                                   domain: str) -> Optional[Dict]:
    """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)  # type: ignore
        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(  # type: ignore
                    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(  # type: ignore
                        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
Example #22
0
def async_prepare_setup_component(hass: core.HomeAssistant, config: dict,
                                  domain: str):
    """Prepare setup of a component and return processed config.

    This method is a coroutine.
    """
    # pylint: disable=too-many-return-statements
    component = loader.get_component(domain)
    missing_deps = [
        dep for dep in getattr(component, 'DEPENDENCIES', [])
        if dep not in hass.config.components
    ]

    if missing_deps:
        _LOGGER.error(
            'Not initializing %s because not all dependencies loaded: %s',
            domain, ", ".join(missing_deps))
        return None

    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 = yield from async_prepare_setup_platform(
                hass, config, domain, p_name)

            if platform is None:
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    # pylint: disable=no-member
                    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

    res = yield from hass.loop.run_in_executor(None, _handle_requirements,
                                               hass, component, domain)
    if not res:
        return None

    return config
Example #23
0
def config_without_domain(config: Dict, domain: str) -> Dict:
    """Return a config with all configuration for a domain removed."""
    filter_keys = extract_domain_configs(config, domain)
    return {key: value for key, value in config.items() if key not in filter_keys}
async def _async_process_config(hass, config, component) -> bool:
    """Process script configuration.

    Return true, if Blueprints were used.
    """
    entities = []
    blueprints_used = False

    for config_key in extract_domain_configs(config, DOMAIN):
        conf: dict[str, dict[str, Any] | BlueprintInputs] = config[config_key]

        for object_id, config_block in conf.items():
            raw_blueprint_inputs = None
            raw_config = None

            if isinstance(config_block, BlueprintInputs):
                blueprints_used = True
                blueprint_inputs = config_block
                raw_blueprint_inputs = blueprint_inputs.config_with_inputs

                try:
                    raw_config = blueprint_inputs.async_substitute()
                    config_block = cast(
                        Dict[str, Any],
                        await async_validate_config_item(hass, raw_config),
                    )
                except vol.Invalid as err:
                    LOGGER.error(
                        "Blueprint %s generated invalid script with input %s: %s",
                        blueprint_inputs.blueprint.name,
                        blueprint_inputs.inputs,
                        humanize_error(config_block, err),
                    )
                    continue
            else:
                raw_config = cast(ScriptConfig, config_block).raw_config

            entities.append(
                ScriptEntity(hass, object_id, config_block, raw_config,
                             raw_blueprint_inputs))

    await component.async_add_entities(entities)

    async def service_handler(service):
        """Execute a service call to script.<script name>."""
        entity_id = ENTITY_ID_FORMAT.format(service.service)
        script_entity = component.get_entity(entity_id)
        await script_entity.async_turn_on(variables=service.data,
                                          context=service.context)

    # Register services for all entities that were created successfully.
    for entity in entities:
        hass.services.async_register(DOMAIN,
                                     entity.object_id,
                                     service_handler,
                                     schema=SCRIPT_SERVICE_SCHEMA)

        # Register the service description
        service_desc = {
            CONF_NAME: entity.name,
            CONF_DESCRIPTION: entity.description,
            CONF_FIELDS: entity.fields,
        }
        async_set_service_schema(hass, DOMAIN, entity.object_id, service_desc)

    return blueprints_used
Example #25
0
def _setup_component(hass, domain, config):
    """Setup a component for Home Assistant."""
    # pylint: disable=too-many-return-statements,too-many-branches
    if domain in hass.config.components:
        return True

    with _SETUP_LOCK:
        # It might have been loaded while waiting for lock
        if domain in hass.config.components:
            return True

        if domain in _CURRENT_SETUP:
            _LOGGER.error('Attempt made to setup %s during setup of %s',
                          domain, domain)
            return False

        component = loader.get_component(domain)
        missing_deps = [
            dep for dep in getattr(component, 'DEPENDENCIES', [])
            if dep not in hass.config.components
        ]

        if missing_deps:
            _LOGGER.error(
                'Not initializing %s because not all dependencies loaded: %s',
                domain, ", ".join(missing_deps))
            return False

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
            except vol.MultipleInvalid as ex:
                cv.log_exception(_LOGGER, ex, domain, config)
                return False

        elif hasattr(component, 'PLATFORM_SCHEMA'):
            platforms = []
            for p_name, p_config in config_per_platform(config, domain):
                # Validate component specific platform schema
                try:
                    p_validated = component.PLATFORM_SCHEMA(p_config)
                except vol.MultipleInvalid as ex:
                    cv.log_exception(_LOGGER, ex, domain, p_config)
                    return False

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

                platform = prepare_setup_platform(hass, config, domain, p_name)

                if platform is None:
                    return False

                # Validate platform specific schema
                if hasattr(platform, 'PLATFORM_SCHEMA'):
                    try:
                        p_validated = platform.PLATFORM_SCHEMA(p_validated)
                    except vol.MultipleInvalid as ex:
                        cv.log_exception(_LOGGER, ex,
                                         '{}.{}'.format(domain,
                                                        p_name), p_validated)
                        return False

                platforms.append(p_validated)

            # Create a copy of the configuration with all config for current
            # component removed and add validated config back in.
            filter_keys = extract_domain_configs(config, domain)
            config = {
                key: value
                for key, value in config.items() if key not in filter_keys
            }
            config[domain] = platforms

        if not _handle_requirements(hass, component, domain):
            return False

        _CURRENT_SETUP.append(domain)

        try:
            if not component.setup(hass, config):
                _LOGGER.error('component %s failed to initialize', domain)
                return False
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception('Error during setup of component %s', domain)
            return False
        finally:
            _CURRENT_SETUP.remove(domain)

        hass.config.components.append(component.DOMAIN)

        # Assumption: if a component does not depend on groups
        # it communicates with devices
        if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []):
            hass.pool.add_worker()

        hass.bus.fire(EVENT_COMPONENT_LOADED,
                      {ATTR_COMPONENT: component.DOMAIN})

        return True
Example #26
0
async def _async_process_config(
    hass: HomeAssistant,
    config: Dict[str, Any],
    component: EntityComponent,
) -> None:
    """Process config and add automations.

    This method is a coroutine.
    """
    entities = []

    for config_key in extract_domain_configs(config, DOMAIN):
        conf: List[Union[Dict[str, Any],
                         blueprint.BlueprintInputs]] = config[  # type: ignore
                             config_key]

        for list_no, config_block in enumerate(conf):
            if isinstance(config_block,
                          blueprint.BlueprintInputs):  # type: ignore
                blueprint_inputs = config_block

                try:
                    config_block = cast(
                        Dict[str, Any],
                        PLATFORM_SCHEMA(blueprint_inputs.async_substitute()),
                    )
                except vol.Invalid as err:
                    _LOGGER.error(
                        "Blueprint %s generated invalid automation with inputs %s: %s",
                        blueprint_inputs.blueprint.name,
                        blueprint_inputs.inputs,
                        humanize_error(config_block, err),
                    )
                    continue

            automation_id = config_block.get(CONF_ID)
            name = config_block.get(CONF_ALIAS) or f"{config_key} {list_no}"

            initial_state = config_block.get(CONF_INITIAL_STATE)

            action_script = Script(
                hass,
                config_block[CONF_ACTION],
                name,
                DOMAIN,
                running_description="automation actions",
                script_mode=config_block[CONF_MODE],
                max_runs=config_block[CONF_MAX],
                max_exceeded=config_block[CONF_MAX_EXCEEDED],
                logger=_LOGGER,
                # We don't pass variables here
                # Automation will already render them to use them in the condition
                # and so will pass them on to the script.
            )

            if CONF_CONDITION in config_block:
                cond_func = await _async_process_if(hass, config, config_block)

                if cond_func is None:
                    continue
            else:
                cond_func = None

            entity = AutomationEntity(
                automation_id,
                name,
                config_block[CONF_TRIGGER],
                cond_func,
                action_script,
                initial_state,
                config_block.get(CONF_VARIABLES),
            )

            entities.append(entity)

    if entities:
        await component.async_add_entities(entities)
Example #27
0
def _setup_component(hass, domain, config):
    """Setup a component for Home Assistant."""
    # pylint: disable=too-many-return-statements,too-many-branches
    if domain in hass.config.components:
        return True

    with _SETUP_LOCK:
        # It might have been loaded while waiting for lock
        if domain in hass.config.components:
            return True

        if domain in _CURRENT_SETUP:
            _LOGGER.error('Attempt made to setup %s during setup of %s',
                          domain, domain)
            return False

        component = loader.get_component(domain)
        missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
                        if dep not in hass.config.components]

        if missing_deps:
            _LOGGER.error(
                'Not initializing %s because not all dependencies loaded: %s',
                domain, ", ".join(missing_deps))
            return False

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
            except vol.MultipleInvalid as ex:
                _LOGGER.error('Invalid config for [%s]: %s', domain, ex)
                return False

        elif hasattr(component, 'PLATFORM_SCHEMA'):
            platforms = []
            for p_name, p_config in config_per_platform(config, domain):
                # Validate component specific platform schema
                try:
                    p_validated = component.PLATFORM_SCHEMA(p_config)
                except vol.MultipleInvalid as ex:
                    _LOGGER.error('Invalid platform config for [%s]: %s. %s',
                                  domain, ex, p_config)
                    return False

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

                platform = prepare_setup_platform(hass, config, domain,
                                                  p_name)

                if platform is None:
                    return False

                # Validate platform specific schema
                if hasattr(platform, 'PLATFORM_SCHEMA'):
                    try:
                        p_validated = platform.PLATFORM_SCHEMA(p_validated)
                    except vol.MultipleInvalid as ex:
                        _LOGGER.error(
                            'Invalid platform config for [%s.%s]: %s. %s',
                            domain, p_name, ex, p_config)
                        return False

                platforms.append(p_validated)

            # Create a copy of the configuration with all config for current
            # component removed and add validated config back in.
            filter_keys = extract_domain_configs(config, domain)
            config = {key: value for key, value in config.items()
                      if key not in filter_keys}
            config[domain] = platforms

        if not _handle_requirements(hass, component, domain):
            return False

        _CURRENT_SETUP.append(domain)

        try:
            if not component.setup(hass, config):
                _LOGGER.error('component %s failed to initialize', domain)
                return False
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception('Error during setup of component %s', domain)
            return False
        finally:
            _CURRENT_SETUP.remove(domain)

        hass.config.components.append(component.DOMAIN)

        # Assumption: if a component does not depend on groups
        # it communicates with devices
        if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []):
            hass.pool.add_worker()

        hass.bus.fire(
            EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN})

        return True