def test_using_prescribed_entity_id_with_unique_id(hass):
    """Test for ammending predefined entity ID because currently exists."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    yield from component.async_add_entities([
        MockEntity(entity_id='test_domain.world')])
    yield from component.async_add_entities([
        MockEntity(entity_id='test_domain.world', unique_id='bla')])

    assert 'test_domain.world_2' in hass.states.async_entity_ids()
def test_not_adding_duplicate_entities_with_unique_id(hass):
    """Test for not adding duplicate entities."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    yield from component.async_add_entities([
        MockEntity(name='test1', unique_id='not_very_unique')])

    assert len(hass.states.async_entity_ids()) == 1

    yield from component.async_add_entities([
        MockEntity(name='test2', unique_id='not_very_unique')])

    assert len(hass.states.async_entity_ids()) == 1
def test_entity_with_name_and_entity_id_getting_registered(hass):
    """Ensure that entity ID is used for registration."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    yield from component.async_add_entities([
        MockEntity(unique_id='1234', name='bla',
                   entity_id='test_domain.world')])
    assert 'test_domain.world' in hass.states.async_entity_ids()
def async_setup(hass, config):
    """Set up input slider."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        minimum = cfg.get(CONF_MIN)
        maximum = cfg.get(CONF_MAX)
        state = cfg.get(CONF_INITIAL, minimum)
        step = cfg.get(CONF_STEP)
        icon = cfg.get(CONF_ICON)
        unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)

        entities.append(InputSlider(object_id, name, state, minimum, maximum, step, icon, unit))

    if not entities:
        return False

    @asyncio.coroutine
    def async_select_value_service(call):
        """Handle a calls to the input slider services."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [input_slider.async_select_value(call.data[ATTR_VALUE]) for input_slider in target_inputs]
        yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(
        DOMAIN, SERVICE_SELECT_VALUE, async_select_value_service, schema=SERVICE_SELECT_VALUE_SCHEMA
    )

    yield from component.async_add_entities(entities)
    return True
Example #5
0
def async_setup(hass, config):
    """Setup input select."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        options = cfg.get(CONF_OPTIONS)
        state = cfg.get(CONF_INITIAL, options[0])
        icon = cfg.get(CONF_ICON)
        entities.append(InputSelect(object_id, name, state, options, icon))

    if not entities:
        return False

    @asyncio.coroutine
    def async_select_option_service(call):
        """Handle a calls to the input select option service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [input_select.async_select_option(call.data[ATTR_OPTION])
                 for input_select in target_inputs]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(
        DOMAIN, SERVICE_SELECT_OPTION, async_select_option_service,
        schema=SERVICE_SELECT_OPTION_SCHEMA)

    @asyncio.coroutine
    def async_select_next_service(call):
        """Handle a calls to the input select next service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [input_select.async_offset_index(1)
                 for input_select in target_inputs]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(
        DOMAIN, SERVICE_SELECT_NEXT, async_select_next_service,
        schema=SERVICE_SELECT_NEXT_SCHEMA)

    @asyncio.coroutine
    def async_select_previous_service(call):
        """Handle a calls to the input select previous service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [input_select.async_offset_index(-1)
                 for input_select in target_inputs]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(
        DOMAIN, SERVICE_SELECT_PREVIOUS, async_select_previous_service,
        schema=SERVICE_SELECT_PREVIOUS_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
def async_setup(hass, config):
    """Set up an input text box."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        minimum = cfg.get(CONF_MIN)
        maximum = cfg.get(CONF_MAX)
        initial = cfg.get(CONF_INITIAL)
        icon = cfg.get(CONF_ICON)
        unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)
        pattern = cfg.get(ATTR_PATTERN)
        mode = cfg.get(CONF_MODE)

        entities.append(InputText(
            object_id, name, initial, minimum, maximum, icon, unit,
            pattern, mode))

    if not entities:
        return False

    component.async_register_entity_service(
        SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA,
        'async_set_value'
    )

    yield from component.async_add_entities(entities)
    return True
def test_not_fails_with_adding_empty_entities_(hass):
    """Test for not fails on empty entities list."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    yield from component.async_add_entities([])

    assert len(hass.states.async_entity_ids()) == 0
def test_async_remove_with_platform(hass):
    """Remove an entity from a platform."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    entity1 = MockEntity(name='test_1')
    yield from component.async_add_entities([entity1])
    assert len(hass.states.async_entity_ids()) == 1
    yield from entity1.async_remove()
    assert len(hass.states.async_entity_ids()) == 0
Example #9
0
def async_setup(hass, config):
    """Set up a timer."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        if not cfg:
            cfg = {}

        name = cfg.get(CONF_NAME)
        icon = cfg.get(CONF_ICON)
        duration = cfg.get(CONF_DURATION)

        entities.append(Timer(hass, object_id, name, icon, duration))

    if not entities:
        return False

    @asyncio.coroutine
    def async_handler_service(service):
        """Handle a call to the timer services."""
        target_timers = component.async_extract_from_service(service)

        attr = None
        if service.service == SERVICE_PAUSE:
            attr = 'async_pause'
        elif service.service == SERVICE_CANCEL:
            attr = 'async_cancel'
        elif service.service == SERVICE_FINISH:
            attr = 'async_finish'

        tasks = [getattr(timer, attr)() for timer in target_timers if attr]
        if service.service == SERVICE_START:
            for timer in target_timers:
                tasks.append(
                    timer.async_start(service.data.get(ATTR_DURATION))
                )
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(
        DOMAIN, SERVICE_START, async_handler_service,
        schema=SERVICE_SCHEMA_DURATION)
    hass.services.async_register(
        DOMAIN, SERVICE_PAUSE, async_handler_service,
        schema=SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_CANCEL, async_handler_service,
        schema=SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_FINISH, async_handler_service,
        schema=SERVICE_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
Example #10
0
def async_setup(hass, config):
    """Load the scripts from the configuration."""
    component = EntityComponent(_LOGGER, DOMAIN, hass,
                                group_name=GROUP_NAME_ALL_SCRIPTS)

    @asyncio.coroutine
    def service_handler(service):
        """Execute a service call to script.<script name>."""
        entity_id = ENTITY_ID_FORMAT.format(service.service)
        script = component.entities.get(entity_id)
        if script.is_on:
            _LOGGER.warning("Script %s already running.", entity_id)
            return
        yield from script.async_turn_on(variables=service.data)

    scripts = []

    for object_id, cfg in config[DOMAIN].items():
        alias = cfg.get(CONF_ALIAS, object_id)
        script = ScriptEntity(hass, object_id, alias, cfg[CONF_SEQUENCE])
        scripts.append(script)
        hass.services.async_register(DOMAIN, object_id, service_handler,
                                     schema=SCRIPT_SERVICE_SCHEMA)

    yield from component.async_add_entities(scripts)

    @asyncio.coroutine
    def turn_on_service(service):
        """Call a service to turn script on."""
        # We could turn on script directly here, but we only want to offer
        # one way to do it. Otherwise no easy way to detect invocations.
        var = service.data.get(ATTR_VARIABLES)
        for script in component.async_extract_from_service(service):
            yield from hass.services.async_call(DOMAIN, script.object_id, var)

    @asyncio.coroutine
    def turn_off_service(service):
        """Cancel a script."""
        # Stopping a script is ok to be done in parallel
        yield from asyncio.wait(
            [script.async_turn_off() for script
             in component.async_extract_from_service(service)], loop=hass.loop)

    @asyncio.coroutine
    def toggle_service(service):
        """Toggle a script."""
        for script in component.async_extract_from_service(service):
            yield from script.async_toggle()

    hass.services.async_register(DOMAIN, SERVICE_TURN_ON, turn_on_service,
                                 schema=SCRIPT_TURN_ONOFF_SCHEMA)
    hass.services.async_register(DOMAIN, SERVICE_TURN_OFF, turn_off_service,
                                 schema=SCRIPT_TURN_ONOFF_SCHEMA)
    hass.services.async_register(DOMAIN, SERVICE_TOGGLE, toggle_service,
                                 schema=SCRIPT_TURN_ONOFF_SCHEMA)
    return True
def async_setup(hass, config):
    """Set up an input boolean."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        if not cfg:
            cfg = {}

        name = cfg.get(CONF_NAME)
        initial = cfg.get(CONF_INITIAL)
        icon = cfg.get(CONF_ICON)

        entities.append(InputBoolean(object_id, name, initial, icon))

    if not entities:
        return False

    @asyncio.coroutine
    def async_handler_service(service):
        """Handle a calls to the input boolean services."""
        target_inputs = component.async_extract_from_service(service)

        if service.service == SERVICE_TURN_ON:
            attr = 'async_turn_on'
        elif service.service == SERVICE_TURN_OFF:
            attr = 'async_turn_off'
        else:
            attr = 'async_toggle'

        tasks = [getattr(input_b, attr)() for input_b in target_inputs]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    descriptions = yield from hass.async_add_job(
        load_yaml_config_file, os.path.join(
            os.path.dirname(__file__), 'services.yaml')
    )

    hass.services.async_register(
        DOMAIN, SERVICE_TURN_OFF, async_handler_service,
        descriptions[DOMAIN][SERVICE_TURN_OFF],
        schema=SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_TURN_ON, async_handler_service,
        descriptions[DOMAIN][SERVICE_TURN_ON],
        schema=SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_TOGGLE, async_handler_service,
        descriptions[DOMAIN][SERVICE_TOGGLE],
        schema=SERVICE_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
Example #12
0
def async_setup(hass, config):
    """Set up a counter."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        if not cfg:
            cfg = {}

        name = cfg.get(CONF_NAME)
        initial = cfg.get(CONF_INITIAL)
        step = cfg.get(CONF_STEP)
        icon = cfg.get(CONF_ICON)

        entities.append(Counter(object_id, name, initial, step, icon))

    if not entities:
        return False

    @asyncio.coroutine
    def async_handler_service(service):
        """Handle a call to the counter services."""
        target_counters = component.async_extract_from_service(service)

        if service.service == SERVICE_INCREMENT:
            attr = 'async_increment'
        elif service.service == SERVICE_DECREMENT:
            attr = 'async_decrement'
        elif service.service == SERVICE_RESET:
            attr = 'async_reset'

        tasks = [getattr(counter, attr)() for counter in target_counters]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    descriptions = yield from hass.async_add_job(
        load_yaml_config_file, os.path.join(
            os.path.dirname(__file__), 'services.yaml')
    )

    hass.services.async_register(
        DOMAIN, SERVICE_INCREMENT, async_handler_service,
        descriptions[SERVICE_INCREMENT], SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_DECREMENT, async_handler_service,
        descriptions[SERVICE_DECREMENT], SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_RESET, async_handler_service,
        descriptions[SERVICE_RESET], SERVICE_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
def test_extract_from_service_returns_all_if_no_entity_id(hass):
    """Test the extraction of everything from service."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    yield from component.async_add_entities([
        MockEntity(name='test_1'),
        MockEntity(name='test_2'),
    ])

    call = ha.ServiceCall('test', 'service')

    assert ['test_domain.test_1', 'test_domain.test_2'] == \
        sorted(ent.entity_id for ent in
               component.async_extract_from_service(call))
def test_name_which_conflict_with_registered(hass):
    """Test not generating conflicting entity ID based on name."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    registry = mock_registry(hass)

    # Register test_domain.world
    registry.async_get_or_create(
        DOMAIN, 'test', '1234', suggested_object_id='world')

    yield from component.async_add_entities([
        MockEntity(name='world')])

    assert 'test_domain.world_2' in hass.states.async_entity_ids()
def test_using_prescribed_entity_id_which_is_registered(hass):
    """Test not allowing predefined entity ID that already registered."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    registry = mock_registry(hass)
    # Register test_domain.world
    registry.async_get_or_create(
        DOMAIN, 'test', '1234', suggested_object_id='world')

    # This entity_id will be rewritten
    yield from component.async_add_entities([
        MockEntity(entity_id='test_domain.world')])

    assert 'test_domain.world_2' in hass.states.async_entity_ids()
def test_extract_from_service_no_group_expand(hass):
    """Test not expanding a group."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    test_group = yield from group.Group.async_create_group(
        hass, 'test_group', ['light.Ceiling', 'light.Kitchen'])
    yield from component.async_add_entities([test_group])

    call = ha.ServiceCall('test', 'service', {
        'entity_id': ['group.test_group']
    })

    extracted = component.async_extract_from_service(call, expand_group=False)
    assert extracted == [test_group]
def test_extract_from_service_filter_out_non_existing_entities(hass):
    """Test the extraction of non existing entities from service."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    yield from component.async_add_entities([
        MockEntity(name='test_1'),
        MockEntity(name='test_2'),
    ])

    call = ha.ServiceCall('test', 'service', {
        'entity_id': ['test_domain.test_2', 'test_domain.non_exist']
    })

    assert ['test_domain.test_2'] == \
           [ent.entity_id for ent
            in component.async_extract_from_service(call)]
def async_setup(hass, config):
    """Set up an input slider."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        minimum = cfg.get(CONF_MIN)
        maximum = cfg.get(CONF_MAX)
        initial = cfg.get(CONF_INITIAL)
        step = cfg.get(CONF_STEP)
        icon = cfg.get(CONF_ICON)
        unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)
        mode = cfg.get(CONF_MODE)

        entities.append(InputNumber(
            object_id, name, initial, minimum, maximum, step, icon, unit,
            mode))

    if not entities:
        return False

    @asyncio.coroutine
    def async_handle_service(service):
        """Handle calls to input_number services."""
        target_inputs = component.async_extract_from_service(service)
        method = SERVICE_TO_METHOD.get(service.service)
        params = service.data.copy()
        params.pop(ATTR_ENTITY_ID, None)

        # call method
        update_tasks = []
        for target_input in target_inputs:
            yield from getattr(target_input, method['method'])(**params)
            if not target_input.should_poll:
                continue
            update_tasks.append(target_input.async_update_ha_state(True))

        if update_tasks:
            yield from asyncio.wait(update_tasks, loop=hass.loop)

    for service, data in SERVICE_TO_METHOD.items():
        hass.services.async_register(
            DOMAIN, service, async_handle_service, schema=data['schema'])

    yield from component.async_add_entities(entities)
    return True
Example #19
0
def async_setup(hass, config):
    """Set up the Plant component."""
    component = EntityComponent(_LOGGER, DOMAIN, hass,
                                group_name=GROUP_NAME_ALL_PLANTS)

    entities = []
    for plant_name, plant_config in config[DOMAIN].items():
        _LOGGER.info("Added plant %s", plant_name)
        entity = Plant(plant_name, plant_config)
        sensor_entity_ids = list(plant_config[CONF_SENSORS].values())
        _LOGGER.debug("Subscribing to entity_ids %s", sensor_entity_ids)
        async_track_state_change(hass, sensor_entity_ids, entity.state_changed)
        entities.append(entity)

    yield from component.async_add_entities(entities)
    return True
def test_updated_state_used_for_entity_id(hass):
    """Test that first update results used for entity ID generation."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    class EntityTestNameFetcher(EntityTest):
        """Mock entity that fetches a friendly name."""

        @asyncio.coroutine
        def async_update(self):
            """Mock update that assigns a name."""
            self._values['name'] = "Living Room"

    yield from component.async_add_entities([EntityTestNameFetcher()], True)

    entity_ids = hass.states.async_entity_ids()
    assert 1 == len(entity_ids)
    assert entity_ids[0] == "test_domain.living_room"
def async_setup(hass, config):
    """Set up an input datetime."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        has_time = cfg.get(CONF_HAS_TIME)
        has_date = cfg.get(CONF_HAS_DATE)
        icon = cfg.get(CONF_ICON)
        initial = cfg.get(CONF_INITIAL)
        entities.append(InputDatetime(object_id, name,
                                      has_date, has_time, icon, initial))

    if not entities:
        return False

    @asyncio.coroutine
    def async_set_datetime_service(call):
        """Handle a call to the input datetime 'set datetime' service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = []
        for input_datetime in target_inputs:
            time = call.data.get(ATTR_TIME)
            date = call.data.get(ATTR_DATE)
            if (input_datetime.has_date() and not date) or \
               (input_datetime.has_time() and not time):
                _LOGGER.error("Invalid service data for "
                              "input_datetime.set_datetime: %s",
                              str(call.data))
                continue

            tasks.append(input_datetime.async_set_datetime(date, time))

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

    hass.services.async_register(
        DOMAIN, SERVICE_SET_DATETIME, async_set_datetime_service,
        schema=SERVICE_SET_DATETIME_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
def test_raise_error_on_update(hass):
    """Test the add entity if they raise an error on update."""
    updates = []
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    entity1 = EntityTest(name='test_1')
    entity2 = EntityTest(name='test_2')

    def _raise():
        """Helper to raise a exception."""
        raise AssertionError

    entity1.update = _raise
    entity2.update = lambda: updates.append(1)

    yield from component.async_add_entities([entity1, entity2], True)

    assert len(updates) == 1
    assert 1 in updates
def test_overriding_name_from_registry(hass):
    """Test that we can override a name via the Entity Registry."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    mock_registry(hass, {
        'test_domain.world': entity_registry.RegistryEntry(
            entity_id='test_domain.world',
            unique_id='1234',
            # Using component.async_add_entities is equal to platform "domain"
            platform='test_domain',
            name='Overridden'
        )
    })
    yield from component.async_add_entities([
        MockEntity(unique_id='1234', name='Device Name')])

    state = hass.states.get('test_domain.world')
    assert state is not None
    assert state.name == 'Overridden'
Example #24
0
def async_setup(hass, config):
    """Set up input boolean."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        if not cfg:
            cfg = DEFAULT_CONFIG

        name = cfg.get(CONF_NAME)
        state = cfg.get(CONF_INITIAL)
        icon = cfg.get(CONF_ICON)

        entities.append(InputBoolean(object_id, name, state, icon))

    if not entities:
        return False

    @asyncio.coroutine
    def async_handler_service(service):
        """Handle a calls to the input boolean services."""
        target_inputs = component.async_extract_from_service(service)

        if service.service == SERVICE_TURN_ON:
            attr = 'async_turn_on'
        elif service.service == SERVICE_TURN_OFF:
            attr = 'async_turn_off'
        else:
            attr = 'async_toggle'

        tasks = [getattr(input_b, attr)() for input_b in target_inputs]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(
        DOMAIN, SERVICE_TURN_OFF, async_handler_service, schema=SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_TURN_ON, async_handler_service, schema=SERVICE_SCHEMA)
    hass.services.async_register(
        DOMAIN, SERVICE_TOGGLE, async_handler_service, schema=SERVICE_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
async def test_set_service_race(hass):
    """Test race condition on setting service."""
    exception = False

    def async_loop_exception_handler(_, _2) -> None:
        """Handle all exception inside the core loop."""
        nonlocal exception
        exception = True

    hass.loop.set_exception_handler(async_loop_exception_handler)

    await async_setup_component(hass, 'group', {})
    component = EntityComponent(_LOGGER, DOMAIN, hass, group_name='yo')

    for i in range(2):
        hass.async_create_task(component.async_add_entities([MockEntity()]))

    await hass.async_block_till_done()
    assert not exception
def async_setup(hass, config):
    """Set up an input text box."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        minimum = cfg.get(CONF_MIN)
        maximum = cfg.get(CONF_MAX)
        initial = cfg.get(CONF_INITIAL)
        icon = cfg.get(CONF_ICON)
        unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)
        pattern = cfg.get(ATTR_PATTERN)

        entities.append(InputText(
            object_id, name, initial, minimum, maximum, icon, unit,
            pattern))

    if not entities:
        return False

    @asyncio.coroutine
    def async_set_value_service(call):
        """Handle a calls to the input box services."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [input_text.async_set_value(call.data[ATTR_VALUE])
                 for input_text in target_inputs]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    descriptions = yield from hass.async_add_job(
        load_yaml_config_file, os.path.join(
            os.path.dirname(__file__), 'services.yaml'))

    hass.services.async_register(
        DOMAIN, SERVICE_SET_VALUE, async_set_value_service,
        description=descriptions[DOMAIN][SERVICE_SET_VALUE],
        schema=SERVICE_SET_VALUE_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
def async_setup(hass, config):
    """Set up an input slider."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        minimum = cfg.get(CONF_MIN)
        maximum = cfg.get(CONF_MAX)
        initial = cfg.get(CONF_INITIAL)
        step = cfg.get(CONF_STEP)
        icon = cfg.get(CONF_ICON)
        unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)
        mode = cfg.get(CONF_MODE)

        entities.append(InputNumber(
            object_id, name, initial, minimum, maximum, step, icon, unit,
            mode))

    if not entities:
        return False

    component.async_register_entity_service(
        SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA,
        'async_set_value'
    )

    component.async_register_entity_service(
        SERVICE_INCREMENT, SERVICE_DEFAULT_SCHEMA,
        'async_increment'
    )

    component.async_register_entity_service(
        SERVICE_DECREMENT, SERVICE_DEFAULT_SCHEMA,
        'async_decrement'
    )

    yield from component.async_add_entities(entities)
    return True
Example #28
0
    def async_setup_platform(p_type, p_config=None, discovery_info=None):
        """Set up a mailbox platform."""
        if p_config is None:
            p_config = {}
        if discovery_info is None:
            discovery_info = {}

        platform = yield from async_prepare_setup_platform(
            hass, config, DOMAIN, p_type)

        if platform is None:
            _LOGGER.error("Unknown mailbox platform specified")
            return

        _LOGGER.info("Setting up %s.%s", DOMAIN, p_type)
        mailbox = None
        try:
            if hasattr(platform, 'async_get_handler'):
                mailbox = yield from \
                    platform.async_get_handler(hass, p_config, discovery_info)
            elif hasattr(platform, 'get_handler'):
                mailbox = yield from hass.async_add_job(
                    platform.get_handler, hass, p_config, discovery_info)
            else:
                raise HomeAssistantError("Invalid mailbox platform.")

            if mailbox is None:
                _LOGGER.error(
                    "Failed to initialize mailbox platform %s", p_type)
                return

        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception('Error setting up platform %s', p_type)
            return

        mailboxes.append(mailbox)
        mailbox_entity = MailboxEntity(hass, mailbox)
        component = EntityComponent(
            logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)
        yield from component.async_add_entities([mailbox_entity])
def async_setup(hass, config):
    """Set up an input select."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        options = cfg.get(CONF_OPTIONS)
        initial = cfg.get(CONF_INITIAL)
        icon = cfg.get(CONF_ICON)
        entities.append(InputSelect(object_id, name, initial, options, icon))

    if not entities:
        return False

    component.async_register_entity_service(
        SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION_SCHEMA,
        'async_select_option'
    )

    component.async_register_entity_service(
        SERVICE_SELECT_NEXT, SERVICE_SELECT_NEXT_SCHEMA,
        lambda entity, call: entity.async_offset_index(1)
    )

    component.async_register_entity_service(
        SERVICE_SELECT_PREVIOUS, SERVICE_SELECT_PREVIOUS_SCHEMA,
        lambda entity, call: entity.async_offset_index(-1)
    )

    component.async_register_entity_service(
        SERVICE_SET_OPTIONS, SERVICE_SET_OPTIONS_SCHEMA,
        'async_set_options'
    )

    yield from component.async_add_entities(entities)
    return True
def test_extract_from_service_available_device(hass):
    """Test the extraction of entity from service and device is available."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    yield from component.async_add_entities([
        MockEntity(name='test_1'),
        MockEntity(name='test_2', available=False),
        MockEntity(name='test_3'),
        MockEntity(name='test_4', available=False),
    ])

    call_1 = ha.ServiceCall('test', 'service')

    assert ['test_domain.test_1', 'test_domain.test_3'] == \
        sorted(ent.entity_id for ent in
               component.async_extract_from_service(call_1))

    call_2 = ha.ServiceCall('test', 'service', data={
        'entity_id': ['test_domain.test_3', 'test_domain.test_4'],
    })

    assert ['test_domain.test_3'] == \
        sorted(ent.entity_id for ent in
               component.async_extract_from_service(call_2))
def test_using_prescribed_entity_id(hass):
    """Test for using predefined entity ID."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    yield from component.async_add_entities(
        [MockEntity(name='bla', entity_id='hello.world')])
    assert 'hello.world' in hass.states.async_entity_ids()
def async_setup(hass: HomeAssistant, config: Dict) -> Generator:
    """Implementation for setting up the component."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    entities = []
    for slug, config in config[DOMAIN].items():
        if not config:
            config = {}

        name = config[NAME]
        hour = config[HOUR]
        minute = config[MINUTE]
        day = None  # type: Optional[int]
        month = None  # type: Optional[int]
        year = None  # type: Optional[int]
        message = config[MESSAGE]
        days_notice = config[DAYS_NOTICE]
        notifier = config[NOTIFIER].replace(NOTIFY_DOMAIN + ".", "")
        countdown = config[COUNTDOWN]
        recurrence = ATTR_DAILY
        if config.get(DAY):
            day = config.get(DAY)
            recurrence = ATTR_MONTHLY
        if config.get(MONTH):
            month = config.get(MONTH)
            recurrence = ATTR_YEARLY
        if config.get(YEAR):
            year = config.get(YEAR)
            calc_date = datetime.datetime.now().replace(second=0,
                                                        microsecond=0)
            notify_date = "{}-{}-{} {}:{}".format(str(year), str(month),
                                                  str(day), str(hour),
                                                  str(minute))
            reminder_set = datetime.datetime.strptime(
                notify_date,
                "%Y-%m-%d %H:%M") + datetime.timedelta(-days_notice)
            if calc_date > reminder_set:
                recurrence = ATTR_PAST_DUE
            else:
                recurrence = ATTR_ON_DATE

        entities.append(
            DateNotifier(
                hass,
                slug,
                name,
                hour,
                minute,
                day,
                month,
                year,
                message,
                days_notice,
                notifier,
                recurrence,
                countdown,
            ))

    @asyncio.coroutine
    def async_scan_dates_service(timestamp: datetime.datetime) -> Generator:
        """Implementation of Home Assistant service for updating entities."""
        for entity in component.entities:
            target_notifiers = [entity]
            tasks = [notifier.scan_dates() for notifier in target_notifiers]
            if tasks:
                yield from asyncio.wait(tasks, loop=hass.loop)
            else:
                _LOGGER.error("no tasks initialized")

    async_track_time_interval(hass, async_scan_dates_service, INTERVAL)

    yield from component.async_add_entities(entities)
    return True
Example #33
0
def async_setup(hass, config):
    """Setup DreamScreen."""
    import pydreamscreen

    config = config.get(DOMAIN, {})

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    @asyncio.coroutine
    def async_handle_dreamscreen_services(service):
        """Reusable DreamScreen service caller."""
        service_definition = SERVICE_TO_ATTRIBUTE.get(service.service)

        attribute = service_definition['attribute']
        attribute_value = service.data.get(service_definition['param'])

        target_entities = yield from component.async_extract_from_service(
            service)

        updates = []
        for entity in target_entities:
            _LOGGER.debug("setting {} {} to {}".format(entity.entity_id,
                                                       attribute,
                                                       attribute_value))
            setattr(entity.device, attribute, attribute_value)
            updates.append(entity.async_update_ha_state(True))

        if updates:
            yield from asyncio.wait(updates, loop=hass.loop)

    for service_name in SERVICE_TO_ATTRIBUTE:
        schema = SERVICE_TO_ATTRIBUTE[service_name].get('schema')
        hass.services.async_register(DOMAIN,
                                     service_name,
                                     async_handle_dreamscreen_services,
                                     schema=schema)

    entities = []
    entity_ids = []
    timeout = config[TIMEOUT_CONF]
    configured = config[DEVICES_CONF]
    _LOGGER.debug("Discovery Timeout: %d" % timeout)
    _LOGGER.debug("Configured devices: %d" % len(configured))
    if len(configured) > 0:
        for deviceConf in configured:
            deviceName = list(deviceConf.keys())[0]
            deviceInfo = deviceConf[deviceName]
            address = deviceInfo[DEVICE_ADDR]
            timeout = deviceInfo[TIMEOUT_CONF]
            _LOGGER.debug("Adding %s - %s [Timeout: %d]" %
                          (deviceName, address, timeout))
            device_state = pydreamscreen.get_state(ip=address, timeout=timeout)
            if device_state == None:
                _LOGGER.warn("Failed to add device [%s] %s. Try setting a 'timeout' in the device config." \
                    % (address, deviceName))
            else:
                _LOGGER.debug("Adding [%s]  %s => State: %s" %
                              (address, deviceName, device_state))
                device = pydreamscreen.get_device(device_state)
                entity = DreamScreenEntity(device=device,
                                           current_ids=entity_ids,
                                           timeout=timeout,
                                           name=deviceName)
                entity_ids.append(entity.entity_id)
                entities.append(entity)
    else:
        _LOGGER.debug("DreamScreen will discover devices.")
        for device in pydreamscreen.get_devices(timeout):
            _LOGGER.info("Discovered device: %s" % device)
            entity = DreamScreenEntity(device=device, current_ids=entity_ids)
            entity_ids.append(entity.entity_id)
            entities.append(entity)

    yield from component.async_add_entities(entities)
    return True
def async_setup(hass, config):
    """Setup input select."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        name = cfg.get(CONF_NAME)
        options = cfg.get(CONF_OPTIONS)
        state = cfg.get(CONF_INITIAL, options[0])
        icon = cfg.get(CONF_ICON)
        entities.append(InputSelect(object_id, name, state, options, icon))

    if not entities:
        return False

    @asyncio.coroutine
    def async_select_option_service(call):
        """Handle a calls to the input select option service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [
            input_select.async_select_option(call.data[ATTR_OPTION])
            for input_select in target_inputs
        ]
        yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(DOMAIN,
                                 SERVICE_SELECT_OPTION,
                                 async_select_option_service,
                                 schema=SERVICE_SELECT_OPTION_SCHEMA)

    @asyncio.coroutine
    def async_select_next_service(call):
        """Handle a calls to the input select next service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [
            input_select.async_offset_index(1)
            for input_select in target_inputs
        ]
        yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(DOMAIN,
                                 SERVICE_SELECT_NEXT,
                                 async_select_next_service,
                                 schema=SERVICE_SELECT_NEXT_SCHEMA)

    @asyncio.coroutine
    def async_select_previous_service(call):
        """Handle a calls to the input select previous service."""
        target_inputs = component.async_extract_from_service(call)

        tasks = [
            input_select.async_offset_index(-1)
            for input_select in target_inputs
        ]
        yield from asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(DOMAIN,
                                 SERVICE_SELECT_PREVIOUS,
                                 async_select_previous_service,
                                 schema=SERVICE_SELECT_PREVIOUS_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
Example #35
0
def async_setup(hass, config):
    """Load the scripts from the configuration."""
    component = EntityComponent(_LOGGER,
                                DOMAIN,
                                hass,
                                group_name=GROUP_NAME_ALL_SCRIPTS)

    @asyncio.coroutine
    def service_handler(service):
        """Execute a service call to script.<script name>."""
        entity_id = ENTITY_ID_FORMAT.format(service.service)
        script = component.entities.get(entity_id)
        if script.is_on:
            _LOGGER.warning("Script %s already running.", entity_id)
            return
        yield from script.async_turn_on(variables=service.data)

    scripts = []

    for object_id, cfg in config[DOMAIN].items():
        alias = cfg.get(CONF_ALIAS, object_id)
        script = ScriptEntity(hass, object_id, alias, cfg[CONF_SEQUENCE])
        scripts.append(script)
        hass.services.async_register(DOMAIN,
                                     object_id,
                                     service_handler,
                                     schema=SCRIPT_SERVICE_SCHEMA)

    yield from component.async_add_entities(scripts)

    @asyncio.coroutine
    def turn_on_service(service):
        """Call a service to turn script on."""
        # We could turn on script directly here, but we only want to offer
        # one way to do it. Otherwise no easy way to detect invocations.
        var = service.data.get(ATTR_VARIABLES)
        for script in component.async_extract_from_service(service):
            yield from hass.services.async_call(DOMAIN, script.object_id, var)

    @asyncio.coroutine
    def turn_off_service(service):
        """Cancel a script."""
        # Stopping a script is ok to be done in parallel
        yield from asyncio.wait([
            script.async_turn_off()
            for script in component.async_extract_from_service(service)
        ],
                                loop=hass.loop)

    @asyncio.coroutine
    def toggle_service(service):
        """Toggle a script."""
        for script in component.async_extract_from_service(service):
            yield from script.async_toggle()

    hass.services.async_register(DOMAIN,
                                 SERVICE_TURN_ON,
                                 turn_on_service,
                                 schema=SCRIPT_TURN_ONOFF_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_TURN_OFF,
                                 turn_off_service,
                                 schema=SCRIPT_TURN_ONOFF_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_TOGGLE,
                                 toggle_service,
                                 schema=SCRIPT_TURN_ONOFF_SCHEMA)
    return True