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
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
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
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
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
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'
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
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
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
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