def setup(bmss, config): """Track states and offer events for sensors.""" component = EntityComponent(logging.getLogger(__name__), DOMAIN, bmss, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) def alarm_service_handler(service): """Map services to methods on Alarm.""" target_alarms = component.extract_from_service(service) code = service.data.get(ATTR_CODE) method = SERVICE_TO_METHOD[service.service] for alarm in target_alarms: getattr(alarm, method)(code) if alarm.should_poll: alarm.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) for service in SERVICE_TO_METHOD: bmss.services.register(DOMAIN, service, alarm_service_handler, descriptions.get(service), schema=ALARM_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for switches.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_SWITCHES) component.setup(config) def handle_switch_service(service): """Handle calls to the switch services.""" target_switches = component.extract_from_service(service) for switch in target_switches: if service.service == SERVICE_TURN_ON: switch.turn_on() elif service.service == SERVICE_TOGGLE: switch.toggle() else: switch.turn_off() if switch.should_poll: switch.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service, descriptions.get(SERVICE_TURN_OFF), schema=SWITCH_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service, descriptions.get(SERVICE_TURN_ON), schema=SWITCH_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_switch_service, descriptions.get(SERVICE_TOGGLE), schema=SWITCH_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for garage door.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_GARAGE_DOORS) component.setup(config) def handle_garage_door_service(service): """Handle calls to the garage door services.""" target_locks = component.extract_from_service(service) for item in target_locks: if service.service == SERVICE_CLOSE: item.close_door() else: item.open_door() if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service, descriptions.get(SERVICE_OPEN), schema=GARAGE_DOOR_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, descriptions.get(SERVICE_CLOSE), schema=GARAGE_DOOR_SERVICE_SCHEMA) return True
def setup(bmss, config): """Track states and offer events for sensors.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, bmss, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) def alarm_service_handler(service): """Map services to methods on Alarm.""" target_alarms = component.extract_from_service(service) code = service.data.get(ATTR_CODE) method = SERVICE_TO_METHOD[service.service] for alarm in target_alarms: getattr(alarm, method)(code) if alarm.should_poll: alarm.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) for service in SERVICE_TO_METHOD: bmss.services.register(DOMAIN, service, alarm_service_handler, descriptions.get(service), schema=ALARM_SERVICE_SCHEMA) return True
def test_setup_recovers_when_setup_raises(self): """Test the setup if exceptions are happening.""" platform1_setup = Mock(side_effect=Exception('Broken')) platform2_setup = Mock(return_value=None) loader.set_component('test_domain.mod1', MockPlatform(platform1_setup)) loader.set_component('test_domain.mod2', MockPlatform(platform2_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) assert not platform1_setup.called assert not platform2_setup.called component.setup( OrderedDict([ (DOMAIN, { 'platform': 'mod1' }), ("{} 2".format(DOMAIN), { 'platform': 'non_exist' }), ("{} 3".format(DOMAIN), { 'platform': 'mod2' }), ])) assert platform1_setup.called assert platform2_setup.called
def setup(hass, config): """Track states and offer events for locks.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LOCKS) component.setup(config) def handle_lock_service(service): """Handle calls to the lock services.""" target_locks = component.extract_from_service(service) code = service.data.get(ATTR_CODE) for item in target_locks: if service.service == SERVICE_LOCK: item.lock(code=code) else: item.unlock(code=code) if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service, descriptions.get(SERVICE_UNLOCK), schema=LOCK_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, descriptions.get(SERVICE_LOCK), schema=LOCK_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for garage door.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_GARAGE_DOORS) component.setup(config) def handle_garage_door_service(service): """Handle calls to the garage door services.""" target_locks = component.extract_from_service(service) for item in target_locks: if service.service == SERVICE_CLOSE: item.close_door() else: item.open_door() if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service, descriptions.get(SERVICE_OPEN), schema=GARAGE_DOOR_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, descriptions.get(SERVICE_CLOSE), schema=GARAGE_DOOR_SERVICE_SCHEMA) return True
def test_setting_up_group(self): """Setup the setting of a group.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass, group_name='everyone') # No group after setup assert 0 == len(self.hass.states.entity_ids()) component.add_entities([EntityTest(name='hello')]) # group exists assert 2 == len(self.hass.states.entity_ids()) assert ['group.everyone'] == self.hass.states.entity_ids('group') group = self.hass.states.get('group.everyone') assert ('test_domain.hello',) == group.attributes.get('entity_id') # group extended component.add_entities([EntityTest(name='hello2')]) assert 3 == len(self.hass.states.entity_ids()) group = self.hass.states.get('group.everyone') assert ['test_domain.hello', 'test_domain.hello2'] == \ sorted(group.attributes.get('entity_id'))
def setup(hass, config): """Track states and offer events for locks.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LOCKS) component.setup(config) def handle_lock_service(service): """Handle calls to the lock services.""" target_locks = component.extract_from_service(service) code = service.data.get(ATTR_CODE) for item in target_locks: if service.service == SERVICE_LOCK: item.lock(code=code) else: item.unlock(code=code) if item.should_poll: item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service, descriptions.get(SERVICE_UNLOCK), schema=LOCK_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, descriptions.get(SERVICE_LOCK), schema=LOCK_SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for binary sensors.""" component = EntityComponent(logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) return True
def setup(hass, config): """Track states and offer events for binary sensors.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) return True
def test_not_assigning_entity_id_if_prescribes_one(self): """Test for not assigning an entity ID.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) assert 'hello.world' not in self.hass.states.entity_ids() component.add_entities([EntityTest(entity_id='hello.world')]) assert 'hello.world' in self.hass.states.entity_ids()
def setup(hass, config): """Setup input select.""" if not isinstance(config.get(DOMAIN), dict): _LOGGER.error('Expected %s config to be a dictionary', DOMAIN) return False component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning( "Found invalid key for boolean input: %s. " "Use %s instead", object_id, slugify(object_id)) continue if not cfg: _LOGGER.warning("No configuration specified for %s", object_id) continue name = cfg.get(CONF_NAME) options = cfg.get(CONF_OPTIONS) if not isinstance(options, list) or len(options) == 0: _LOGGER.warning('Key %s should be a list of options', CONF_OPTIONS) continue options = [str(val) for val in options] state = cfg.get(CONF_INITIAL) if state not in options: state = options[0] icon = cfg.get(CONF_ICON) entities.append(InputSelect(object_id, name, state, options, icon)) if not entities: return False def select_option_service(call): """Handle a calls to the input select services.""" target_inputs = component.extract_from_service(call) for input_select in target_inputs: input_select.select_option(call.data[ATTR_OPTION]) hass.services.register(DOMAIN, SERVICE_SELECT_OPTION, select_option_service, schema=SERVICE_SELECT_OPTION_SCHEMA) component.add_entities(entities) return True
def setup(hass, config): """Set up input slider.""" if not isinstance(config.get(DOMAIN), dict): _LOGGER.error('Expected %s config to be a dictionary', DOMAIN) return False component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning( "Found invalid key for boolean input: %s. " "Use %s instead", object_id, slugify(object_id)) continue if not cfg: _LOGGER.warning("No configuration specified for %s", object_id) continue 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, 1) icon = cfg.get(CONF_ICON) unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT) if state < minimum: state = minimum if state > maximum: state = maximum entities.append( InputSlider(object_id, name, state, minimum, maximum, step, icon, unit)) if not entities: return False def select_value_service(call): """Handle a calls to the input slider services.""" target_inputs = component.extract_from_service(call) for input_slider in target_inputs: input_slider.select_value(call.data[ATTR_VALUE]) hass.services.register(DOMAIN, SERVICE_SELECT_VALUE, select_value_service, schema=SERVICE_SELECT_VALUE_SCHEMA) component.add_entities(entities) return True
def setup(hass, config): """Setup the camera component.""" component = EntityComponent(logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) hass.wsgi.register_view(CameraImageView(hass, component.entities)) hass.wsgi.register_view(CameraMjpegStream(hass, component.entities)) component.setup(config) return True
def setup(hass, config): """Load the scripts from the configuration.""" component = EntityComponent(_LOGGER, DOMAIN, hass) 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 script.turn_on(variables=service.data) for object_id, cfg in config[DOMAIN].items(): alias = cfg.get(CONF_ALIAS, object_id) script = ScriptEntity(hass, object_id, alias, cfg[CONF_SEQUENCE]) component.add_entities((script, )) hass.services.register(DOMAIN, object_id, service_handler, schema=SCRIPT_SERVICE_SCHEMA) 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. for script in component.extract_from_service(service): turn_on(hass, script.entity_id, service.data.get(ATTR_VARIABLES)) def turn_off_service(service): """Cancel a script.""" for script in component.extract_from_service(service): script.turn_off() def toggle_service(service): """Toggle a script.""" for script in component.extract_from_service(service): script.toggle() hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) return True
def test_extract_from_service_returns_all_if_no_entity_id(self): """Test the extraction of everything from service.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.add_entities([ EntityTest(name='test_1'), EntityTest(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.extract_from_service(call))
def test_not_adding_duplicate_entities(self): """Test for not adding duplicate entities.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) assert 0 == len(self.hass.states.entity_ids()) component.add_entities([None, EntityTest(unique_id='not_very_unique')]) assert 1 == len(self.hass.states.entity_ids()) component.add_entities([EntityTest(unique_id='not_very_unique')]) assert 1 == len(self.hass.states.entity_ids())
def setup(hass, config): """Set up input boolean.""" if not isinstance(config.get(DOMAIN), dict): _LOGGER.error('Expected %s config to be a dictionary', DOMAIN) return False component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning( "Found invalid key for boolean input: %s. " "Use %s instead", object_id, slugify(object_id)) continue if not cfg: cfg = {} name = cfg.get(CONF_NAME) state = cfg.get(CONF_INITIAL, False) icon = cfg.get(CONF_ICON) entities.append(InputBoolean(object_id, name, state, icon)) if not entities: return False def toggle_service(service): """Handle a calls to the input boolean services.""" target_inputs = component.extract_from_service(service) for input_b in target_inputs: if service.service == SERVICE_TURN_ON: input_b.turn_on() else: input_b.turn_off() hass.services.register(DOMAIN, SERVICE_TURN_OFF, toggle_service, schema=TOGGLE_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_ON, toggle_service, schema=TOGGLE_SERVICE_SCHEMA) component.add_entities(entities) return True
def test_extract_from_service_filter_out_non_existing_entities(self): """Test the extraction of non existing entities from service.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.add_entities([ EntityTest(name='test_1'), EntityTest(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.extract_from_service(call)]
def test_extract_from_service_filter_out_non_existing_entities(self): """Test the extraction of non existing entities from service.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.add_entities([ EntityTest(name='test_1'), EntityTest(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.extract_from_service(call)]
def test_update_state_adds_entities(self): """Test if updating poll entities cause an entity to be added works.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) ent1 = EntityTest() ent2 = EntityTest(should_poll=True) component.add_entities([ent2]) assert 1 == len(self.hass.states.entity_ids()) ent2.update_ha_state = lambda *_: component.add_entities([ent1]) fire_time_changed(self.hass, dt_util.utcnow().replace(second=0)) self.hass.pool.block_till_done() assert 2 == len(self.hass.states.entity_ids())
def setup(hass, config): """Set up input boolean.""" if not isinstance(config.get(DOMAIN), dict): _LOGGER.error('Expected %s config to be a dictionary', DOMAIN) return False component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning("Found invalid key for boolean input: %s. " "Use %s instead", object_id, slugify(object_id)) continue if not cfg: cfg = {} name = cfg.get(CONF_NAME) state = cfg.get(CONF_INITIAL, False) icon = cfg.get(CONF_ICON) entities.append(InputBoolean(object_id, name, state, icon)) if not entities: return False def toggle_service(service): """Handle a calls to the input boolean services.""" target_inputs = component.extract_from_service(service) for input_b in target_inputs: if service.service == SERVICE_TURN_ON: input_b.turn_on() else: input_b.turn_off() hass.services.register(DOMAIN, SERVICE_TURN_OFF, toggle_service, schema=TOGGLE_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_ON, toggle_service, schema=TOGGLE_SERVICE_SCHEMA) component.add_entities(entities) return True
def setup(hass, config): """Load the scripts from the configuration.""" component = EntityComponent(_LOGGER, DOMAIN, hass) 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 script.turn_on(variables=service.data) for object_id, cfg in config[DOMAIN].items(): alias = cfg.get(CONF_ALIAS, object_id) script = ScriptEntity(hass, object_id, alias, cfg[CONF_SEQUENCE]) component.add_entities((script,)) hass.services.register(DOMAIN, object_id, service_handler, schema=SCRIPT_SERVICE_SCHEMA) 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. for script in component.extract_from_service(service): turn_on(hass, script.entity_id, service.data.get(ATTR_VARIABLES)) def turn_off_service(service): """Cancel a script.""" for script in component.extract_from_service(service): script.turn_off() def toggle_service(service): """Toggle a script.""" for script in component.extract_from_service(service): script.toggle() hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) return True
def test_polling_only_updates_entities_it_should_poll(self): """Test the polling of only updated entities.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass, 20) no_poll_ent = EntityTest(should_poll=False) no_poll_ent.update_ha_state = Mock() poll_ent = EntityTest(should_poll=True) poll_ent.update_ha_state = Mock() component.add_entities([no_poll_ent, poll_ent]) no_poll_ent.update_ha_state.reset_mock() poll_ent.update_ha_state.reset_mock() fire_time_changed(self.hass, dt_util.utcnow().replace(second=0)) self.hass.pool.block_till_done() assert not no_poll_ent.update_ha_state.called assert poll_ent.update_ha_state.called
def test_setup_does_discovery(self, mock_setup): """Test setup for discovery.""" component = EntityComponent( _LOGGER, DOMAIN, self.hass, discovery_platforms={ 'discovery.test': 'platform_test', }) component.setup({}) self.hass.bus.fire(discovery.EVENT_PLATFORM_DISCOVERED, { discovery.ATTR_SERVICE: 'discovery.test', discovery.ATTR_DISCOVERED: 'discovery_info', }) self.hass.pool.block_till_done() assert mock_setup.called assert ('platform_test', {}, 'discovery_info') == \ mock_setup.call_args[0]
def test_set_scan_interval_via_platform(self, mock_track): """Test the setting of the scan interval via platform.""" def platform_setup(hass, config, add_devices, discovery_info=None): """Test the platform setup.""" add_devices([EntityTest(should_poll=True)]) platform = MockPlatform(platform_setup) platform.SCAN_INTERVAL = 30 loader.set_component('test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.setup({DOMAIN: { 'platform': 'platform', }}) assert mock_track.called assert [0, 30] == list(mock_track.call_args[1]['second'])
def test_set_scan_interval_via_config(self, mock_track): """Test the setting of the scan interval via configuration.""" def platform_setup(hass, config, add_devices, discovery_info=None): """Test the platform setup.""" add_devices([EntityTest(should_poll=True)]) loader.set_component('test_domain.platform', MockPlatform(platform_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.setup({ DOMAIN: { 'platform': 'platform', 'scan_interval': 30, } }) assert mock_track.called assert [0, 30] == list(mock_track.call_args[1]['second'])
def test_setup_recovers_when_setup_raises(self): """Test the setup if exceptions are happening.""" platform1_setup = Mock(side_effect=Exception('Broken')) platform2_setup = Mock(return_value=None) loader.set_component('test_domain.mod1', MockPlatform(platform1_setup)) loader.set_component('test_domain.mod2', MockPlatform(platform2_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) assert not platform1_setup.called assert not platform2_setup.called component.setup(OrderedDict([ (DOMAIN, {'platform': 'mod1'}), ("{} 2".format(DOMAIN), {'platform': 'non_exist'}), ("{} 3".format(DOMAIN), {'platform': 'mod2'}), ])) assert platform1_setup.called assert platform2_setup.called
def test_setup_loads_platforms(self): """Test the loading of the platforms.""" component_setup = Mock(return_value=True) platform_setup = Mock(return_value=None) loader.set_component( 'test_component', MockModule('test_component', setup=component_setup)) loader.set_component('test_domain.mod2', MockPlatform(platform_setup, ['test_component'])) component = EntityComponent(_LOGGER, DOMAIN, self.hass) assert not component_setup.called assert not platform_setup.called component.setup({DOMAIN: { 'platform': 'mod2', }}) assert component_setup.called assert platform_setup.called
def test_setting_up_group(self): """Setup the setting of a group.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass, group_name='everyone') # No group after setup assert 0 == len(self.hass.states.entity_ids()) component.add_entities([EntityTest(name='hello')]) # group exists assert 2 == len(self.hass.states.entity_ids()) assert ['group.everyone'] == self.hass.states.entity_ids('group') group = self.hass.states.get('group.everyone') assert ('test_domain.hello', ) == group.attributes.get('entity_id') # group extended component.add_entities([EntityTest(name='hello2')]) assert 3 == len(self.hass.states.entity_ids()) group = self.hass.states.get('group.everyone') assert ['test_domain.hello', 'test_domain.hello2'] == \ sorted(group.attributes.get('entity_id'))
def test_setup_does_discovery(self, mock_setup): """Test setup for discovery.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass, discovery_platforms={ 'discovery.test': 'platform_test', }) component.setup({}) self.hass.bus.fire( discovery.EVENT_PLATFORM_DISCOVERED, { discovery.ATTR_SERVICE: 'discovery.test', discovery.ATTR_DISCOVERED: 'discovery_info', }) self.hass.pool.block_till_done() assert mock_setup.called assert ('platform_test', {}, 'discovery_info') == \ mock_setup.call_args[0]
def setup(hass, config): """Track states and offer events for roller shutters.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_ROLLERSHUTTERS) component.setup(config) def handle_rollershutter_service(service): """Handle calls to the roller shutter services.""" target_rollershutters = component.extract_from_service(service) for rollershutter in target_rollershutters: if service.service == SERVICE_MOVE_UP: rollershutter.move_up() elif service.service == SERVICE_MOVE_DOWN: rollershutter.move_down() elif service.service == SERVICE_STOP: rollershutter.stop() if rollershutter.should_poll: rollershutter.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_MOVE_UP, handle_rollershutter_service, descriptions.get(SERVICE_MOVE_UP), schema=ROLLERSHUTTER_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_MOVE_DOWN, handle_rollershutter_service, descriptions.get(SERVICE_MOVE_DOWN), schema=ROLLERSHUTTER_SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_STOP, handle_rollershutter_service, descriptions.get(SERVICE_STOP), schema=ROLLERSHUTTER_SERVICE_SCHEMA) return True
def test_set_entity_namespace_via_config(self): """Test setting an entity namespace.""" def platform_setup(hass, config, add_devices, discovery_info=None): """Test the platform setup.""" add_devices([ EntityTest(name='beer'), EntityTest(name=None), ]) platform = MockPlatform(platform_setup) loader.set_component('test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.setup( {DOMAIN: { 'platform': 'platform', 'entity_namespace': 'yummy' }}) assert sorted(self.hass.states.entity_ids()) == \ ['test_domain.yummy_beer', 'test_domain.yummy_unnamed_device']
def test_setup_loads_platforms(self): """Test the loading of the platforms.""" component_setup = Mock(return_value=True) platform_setup = Mock(return_value=None) loader.set_component( 'test_component', MockModule('test_component', setup=component_setup)) loader.set_component('test_domain.mod2', MockPlatform(platform_setup, ['test_component'])) component = EntityComponent(_LOGGER, DOMAIN, self.hass) assert not component_setup.called assert not platform_setup.called component.setup({ DOMAIN: { 'platform': 'mod2', } }) assert component_setup.called assert platform_setup.called
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': 'blumate', '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
def test_set_entity_namespace_via_config(self): """Test setting an entity namespace.""" def platform_setup(hass, config, add_devices, discovery_info=None): """Test the platform setup.""" add_devices([ EntityTest(name='beer'), EntityTest(name=None), ]) platform = MockPlatform(platform_setup) loader.set_component('test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.setup({ DOMAIN: { 'platform': 'platform', 'entity_namespace': 'yummy' } }) assert sorted(self.hass.states.entity_ids()) == \ ['test_domain.yummy_beer', 'test_domain.yummy_unnamed_device']
def setup(hass, config): """Setup thermostats.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target thermostats.""" target_thermostats = component.extract_from_service(service) away_mode = service.data[ATTR_AWAY_MODE] for thermostat in target_thermostats: if away_mode: thermostat.turn_away_mode_on() else: thermostat.turn_away_mode_off() thermostat.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE), schema=SET_AWAY_MODE_SCHEMA) def temperature_set_service(service): """Set temperature on the target thermostats.""" target_thermostats = component.extract_from_service(service) temperature = service.data[ATTR_TEMPERATURE] for thermostat in target_thermostats: thermostat.set_temperature(convert( temperature, hass.config.temperature_unit, thermostat.unit_of_measurement)) thermostat.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE), schema=SET_TEMPERATURE_SCHEMA) def fan_mode_set_service(service): """Set fan mode on target thermostats.""" target_thermostats = component.extract_from_service(service) fan_mode = service.data[ATTR_FAN] for thermostat in target_thermostats: if fan_mode: thermostat.turn_fan_on() else: thermostat.turn_fan_off() thermostat.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE), schema=SET_FAN_MODE_SCHEMA) return True
def setup(hass, config): """Setup hvacs.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target hvacs.""" target_hvacs = component.extract_from_service(service) away_mode = service.data.get(ATTR_AWAY_MODE) if away_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) return for hvac in target_hvacs: if away_mode: hvac.turn_away_mode_on() else: hvac.turn_away_mode_off() if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE)) def aux_heat_set_service(service): """Set auxillary heater on target hvacs.""" target_hvacs = component.extract_from_service(service) aux_heat = service.data.get(ATTR_AUX_HEAT) if aux_heat is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_AUX_HEAT, ATTR_AUX_HEAT) return for hvac in target_hvacs: if aux_heat: hvac.turn_aux_heat_on() else: hvac.turn_aux_heat_off() if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_AUX_HEAT, aux_heat_set_service, descriptions.get(SERVICE_SET_AUX_HEAT)) def temperature_set_service(service): """Set temperature on the target hvacs.""" target_hvacs = component.extract_from_service(service) temperature = util.convert( service.data.get(ATTR_TEMPERATURE), float) if temperature is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_TEMPERATURE, ATTR_TEMPERATURE) return for hvac in target_hvacs: hvac.set_temperature(convert( temperature, hass.config.temperature_unit, hvac.unit_of_measurement)) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE)) def humidity_set_service(service): """Set humidity on the target hvacs.""" target_hvacs = component.extract_from_service(service) humidity = service.data.get(ATTR_HUMIDITY) if humidity is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_HUMIDITY, ATTR_HUMIDITY) return for hvac in target_hvacs: hvac.set_humidity(humidity) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_HUMIDITY, humidity_set_service, descriptions.get(SERVICE_SET_HUMIDITY)) def fan_mode_set_service(service): """Set fan mode on target hvacs.""" target_hvacs = component.extract_from_service(service) fan = service.data.get(ATTR_FAN_MODE) if fan is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_FAN_MODE, ATTR_FAN_MODE) return for hvac in target_hvacs: hvac.set_fan_mode(fan) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE)) def operation_set_service(service): """Set operating mode on the target hvacs.""" target_hvacs = component.extract_from_service(service) operation_mode = service.data.get(ATTR_OPERATION_MODE) if operation_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_OPERATION_MODE, ATTR_OPERATION_MODE) return for hvac in target_hvacs: hvac.set_operation_mode(operation_mode) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_OPERATION_MODE, operation_set_service, descriptions.get(SERVICE_SET_OPERATION_MODE)) def swing_set_service(service): """Set swing mode on the target hvacs.""" target_hvacs = component.extract_from_service(service) swing_mode = service.data.get(ATTR_SWING_MODE) if swing_mode is None: _LOGGER.error( "Received call to %s without attribute %s", SERVICE_SET_SWING_MODE, ATTR_SWING_MODE) return for hvac in target_hvacs: hvac.set_swing_mode(swing_mode) if hvac.should_poll: hvac.update_ha_state(True) hass.services.register( DOMAIN, SERVICE_SET_SWING_MODE, swing_set_service, descriptions.get(SERVICE_SET_SWING_MODE)) return True
def setup(hass, config): """Track states and offer events for media_players.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def media_player_service_handler(service): """Map services to methods on MediaPlayerDevice.""" method = SERVICE_TO_METHOD[service.service] for player in component.extract_from_service(service): getattr(player, method)() if player.should_poll: player.update_ha_state(True) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, media_player_service_handler, descriptions.get(service), schema=MEDIA_PLAYER_SCHEMA) def volume_set_service(service): """Set specified volume on the media player.""" volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) for player in component.extract_from_service(service): player.set_volume_level(volume) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service, descriptions.get(SERVICE_VOLUME_SET), schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA) def volume_mute_service(service): """Mute (true) or unmute (false) the media player.""" mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED) for player in component.extract_from_service(service): player.mute_volume(mute) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service, descriptions.get(SERVICE_VOLUME_MUTE), schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA) def media_seek_service(service): """Seek to a position.""" position = service.data.get(ATTR_MEDIA_SEEK_POSITION) for player in component.extract_from_service(service): player.media_seek(position) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service, descriptions.get(SERVICE_MEDIA_SEEK), schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA) def select_source_service(service): """Change input to selected source.""" input_source = service.data.get(ATTR_INPUT_SOURCE) for player in component.extract_from_service(service): player.select_source(input_source) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE, select_source_service, descriptions.get(SERVICE_SELECT_SOURCE), schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA) def play_media_service(service): """Play specified media_id on the media player.""" media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE) media_id = service.data.get(ATTR_MEDIA_CONTENT_ID) enqueue = service.data.get(ATTR_MEDIA_ENQUEUE) kwargs = { ATTR_MEDIA_ENQUEUE: enqueue, } for player in component.extract_from_service(service): player.play_media(media_type, media_id, **kwargs) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service, descriptions.get(SERVICE_PLAY_MEDIA), schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA) return True
def setup(hass, config): """Setup thermostats.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target thermostats.""" target_thermostats = component.extract_from_service(service) away_mode = service.data[ATTR_AWAY_MODE] for thermostat in target_thermostats: if away_mode: thermostat.turn_away_mode_on() else: thermostat.turn_away_mode_off() thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE), schema=SET_AWAY_MODE_SCHEMA) def temperature_set_service(service): """Set temperature on the target thermostats.""" target_thermostats = component.extract_from_service(service) temperature = service.data[ATTR_TEMPERATURE] for thermostat in target_thermostats: thermostat.set_temperature( convert(temperature, hass.config.temperature_unit, thermostat.unit_of_measurement)) thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE), schema=SET_TEMPERATURE_SCHEMA) def fan_mode_set_service(service): """Set fan mode on target thermostats.""" target_thermostats = component.extract_from_service(service) fan_mode = service.data[ATTR_FAN] for thermostat in target_thermostats: if fan_mode: thermostat.turn_fan_on() else: thermostat.turn_fan_off() thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE), schema=SET_FAN_MODE_SCHEMA) return True
def setup(hass, config): """Expose light control via statemachine and services.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_LIGHTS) component.setup(config) # Load built-in profiles and custom profiles profile_paths = [os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE), hass.config.path(LIGHT_PROFILES_FILE)] profiles = {} for profile_path in profile_paths: if not os.path.isfile(profile_path): continue with open(profile_path) as inp: reader = csv.reader(inp) # Skip the header next(reader, None) try: for rec in reader: profile, color_x, color_y, brightness = PROFILE_SCHEMA(rec) profiles[profile] = (color_x, color_y, brightness) except vol.MultipleInvalid as ex: _LOGGER.error("Error parsing light profile from %s: %s", profile_path, ex) return False def handle_light_service(service): """Hande a turn light on or off service call.""" # Get the validated data params = service.data.copy() # Convert the entity ids to valid light ids target_lights = component.extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) service_fun = None if service.service == SERVICE_TURN_OFF: service_fun = 'turn_off' elif service.service == SERVICE_TOGGLE: service_fun = 'toggle' if service_fun: for light in target_lights: getattr(light, service_fun)(**params) for light in target_lights: if light.should_poll: light.update_ha_state(True) return # Processing extra data for turn light on request. profile = profiles.get(params.pop(ATTR_PROFILE, None)) if profile: params.setdefault(ATTR_XY_COLOR, profile[:2]) params.setdefault(ATTR_BRIGHTNESS, profile[2]) color_name = params.pop(ATTR_COLOR_NAME, None) if color_name is not None: params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name) for light in target_lights: light.turn_on(**params) for light in target_lights: if light.should_poll: light.update_ha_state(True) # Listen for light on and light off service calls. descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_light_service, descriptions.get(SERVICE_TURN_ON), schema=LIGHT_TURN_ON_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service, descriptions.get(SERVICE_TURN_OFF), schema=LIGHT_TURN_OFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_light_service, descriptions.get(SERVICE_TOGGLE), schema=LIGHT_TOGGLE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for media_players.""" component = EntityComponent(logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def media_player_service_handler(service): """Map services to methods on MediaPlayerDevice.""" method = SERVICE_TO_METHOD[service.service] for player in component.extract_from_service(service): getattr(player, method)() if player.should_poll: player.update_ha_state(True) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, media_player_service_handler, descriptions.get(service), schema=MEDIA_PLAYER_SCHEMA) def volume_set_service(service): """Set specified volume on the media player.""" volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) for player in component.extract_from_service(service): player.set_volume_level(volume) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service, descriptions.get(SERVICE_VOLUME_SET), schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA) def volume_mute_service(service): """Mute (true) or unmute (false) the media player.""" mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED) for player in component.extract_from_service(service): player.mute_volume(mute) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service, descriptions.get(SERVICE_VOLUME_MUTE), schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA) def media_seek_service(service): """Seek to a position.""" position = service.data.get(ATTR_MEDIA_SEEK_POSITION) for player in component.extract_from_service(service): player.media_seek(position) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service, descriptions.get(SERVICE_MEDIA_SEEK), schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA) def select_source_service(service): """Change input to selected source.""" input_source = service.data.get(ATTR_INPUT_SOURCE) for player in component.extract_from_service(service): player.select_source(input_source) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE, select_source_service, descriptions.get(SERVICE_SELECT_SOURCE), schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA) def play_media_service(service): """Play specified media_id on the media player.""" media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE) media_id = service.data.get(ATTR_MEDIA_CONTENT_ID) enqueue = service.data.get(ATTR_MEDIA_ENQUEUE) kwargs = { ATTR_MEDIA_ENQUEUE: enqueue, } for player in component.extract_from_service(service): player.play_media(media_type, media_id, **kwargs) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service, descriptions.get(SERVICE_PLAY_MEDIA), schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA) return True
def setup(bmss, config): component = EntityComponent( logging.getLogger(__name__), DOMAIN, bmss, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config)