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 len(self.hass.states.entity_ids()) == 0 component.add_entities([EntityTest(name='hello')]) # group exists assert len(self.hass.states.entity_ids()) == 2 assert self.hass.states.entity_ids('group') == ['group.everyone'] group = self.hass.states.get('group.everyone') assert group.attributes.get('entity_id') == ('test_domain.hello',) # group extended component.add_entities([EntityTest(name='hello2')]) assert len(self.hass.states.entity_ids()) == 3 group = self.hass.states.get('group.everyone') assert sorted(group.attributes.get('entity_id')) == \ ['test_domain.hello', 'test_domain.hello2']
def setup(hass, config): """ Sets up scenes. """ logger = logging.getLogger(__name__) scene_configs = config.get(DOMAIN) if not isinstance(scene_configs, list) or \ any(not isinstance(item, dict) for item in scene_configs): logger.error('Scene config should be a list of dictionaries') return False component = EntityComponent(logger, DOMAIN, hass) component.add_entities(Scene(hass, _process_config(scene_config)) for scene_config in scene_configs) def handle_scene_service(service): """ Handles 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) return True
def 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 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 test_setting_up_group(self): 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_setting_up_group(self): """Setup the setting of a group.""" setup_component(self.hass, 'group', {'group': {}}) component = EntityComponent(_LOGGER, DOMAIN, self.hass, group_name='everyone') # No group after setup assert len(self.hass.states.entity_ids()) == 0 component.add_entities([MockEntity()]) self.hass.block_till_done() # group exists assert len(self.hass.states.entity_ids()) == 2 assert self.hass.states.entity_ids('group') == ['group.everyone'] group = self.hass.states.get('group.everyone') assert group.attributes.get('entity_id') == \ ('test_domain.unnamed_device',) # group extended component.add_entities([MockEntity(name='goodbye')]) self.hass.block_till_done() assert len(self.hass.states.entity_ids()) == 3 group = self.hass.states.get('group.everyone') # Ordered in order of added to the group assert group.attributes.get('entity_id') == \ ('test_domain.goodbye', 'test_domain.unnamed_device')
def 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 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 test_not_assigning_entity_id_if_prescribes_one(self): 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 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_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 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 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 test_update_state_adds_entities_with_update_befor_add_false(self): """Test if not call update befor add to state machine.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) ent = EntityTest() ent.update = Mock(spec_set=True) component.add_entities([ent], False) self.hass.block_till_done() assert 1 == len(self.hass.states.entity_ids()) assert not ent.update.called
def test_extract_from_service_returns_all_if_no_entity_id(self): 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): 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 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) step = cfg.get(CONF_STEP) icon = cfg.get(CONF_ICON) if state < minimum: state = minimum if state > maximum: state = maximum entities.append( InputSlider(object_id, name, state, minimum, maximum, step, icon) ) 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): """ 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 not script: return if script.is_on: _LOGGER.warning("Script %s already running.", entity_id) return script.turn_on() for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): _LOGGER.warning("Found invalid key for script: %s. Use %s instead", object_id, slugify(object_id)) continue if not isinstance(cfg.get(CONF_SEQUENCE), list): _LOGGER.warning("Key 'sequence' for script %s should be a list", object_id) continue alias = cfg.get(CONF_ALIAS, object_id) script = Script(object_id, alias, cfg[CONF_SEQUENCE]) component.add_entities((script,)) hass.services.register(DOMAIN, object_id, service_handler) def turn_on_service(service): """ Calls 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 call invocations. for script in component.extract_from_service(service): turn_on(hass, script.entity_id) def turn_off_service(service): """ Cancels a script. """ for script in component.extract_from_service(service): script.turn_off() def toggle_service(service): """ Toggles a script. """ for script in component.extract_from_service(service): script.toggle() hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service) hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service) hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service) return True
def test_extract_from_service_no_group_expand(self): """Test not expanding a group.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass) test_group = group.Group.create_group( self.hass, 'test_group', ['light.Ceiling', 'light.Kitchen']) component.add_entities([test_group]) call = ha.ServiceCall('test', 'service', { 'entity_id': ['group.test_group'] }) extracted = component.extract_from_service(call, expand_group=False) self.assertEqual([test_group], extracted)
def test_extract_from_service_filter_out_non_existing_entities(self): 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 test_adding_entities_with_generator_and_thread_callback(self): """Test generator in add_entities that calls thread method. We should make sure we resolve the generator to a list before passing it into an async context. """ component = EntityComponent(_LOGGER, DOMAIN, self.hass) def create_entity(number): """Create entity helper.""" entity = EntityTest() entity.entity_id = generate_entity_id(component.entity_id_format, 'Number', hass=self.hass) return entity component.add_entities(create_entity(i) for i in range(2))
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 = MockEntity() ent2 = MockEntity(should_poll=True) component.add_entities([ent2]) assert 1 == len(self.hass.states.entity_ids()) ent2.update = lambda *_: component.add_entities([ent1]) fire_time_changed( self.hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL ) self.hass.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, group_name=GROUP_NAME_ALL_SCRIPTS) 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): 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_polling_only_updates_entities_it_should_poll(self): """Test the polling of only updated entities.""" component = EntityComponent( _LOGGER, DOMAIN, self.hass, timedelta(seconds=20)) no_poll_ent = EntityTest(should_poll=False) no_poll_ent.async_update = Mock() poll_ent = EntityTest(should_poll=True) poll_ent.async_update = Mock() component.add_entities([no_poll_ent, poll_ent]) no_poll_ent.async_update.reset_mock() poll_ent.async_update.reset_mock() fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20)) self.hass.block_till_done() assert not no_poll_ent.async_update.called assert poll_ent.async_update.called
def 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 = {} 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 handler_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() elif service.service == SERVICE_TURN_OFF: input_b.turn_off() else: input_b.toggle() hass.services.register(DOMAIN, SERVICE_TURN_OFF, handler_service, schema=SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TURN_ON, handler_service, schema=SERVICE_SCHEMA) hass.services.register(DOMAIN, SERVICE_TOGGLE, handler_service, schema=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: script.turn_on() for name, cfg in config[DOMAIN].items(): if not cfg.get(CONF_SEQUENCE): _LOGGER.warn("Missing key 'sequence' for script %s", name) continue alias = cfg.get(CONF_ALIAS, name) script = Script(hass, alias, cfg[CONF_SEQUENCE]) component.add_entities((script,)) _, object_id = split_entity_id(script.entity_id) hass.services.register(DOMAIN, object_id, service_handler) def turn_on_service(service): """ Calls 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 call invocations. for script in component.extract_from_service(service): turn_on(hass, script.entity_id) def turn_off_service(service): """ Cancels a script. """ for script in component.extract_from_service(service): script.turn_off() hass.services.register(DOMAIN, SERVICE_TURN_ON, turn_on_service) hass.services.register(DOMAIN, SERVICE_TURN_OFF, turn_off_service) return True
def setUp(self): """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() component = EntityComponent(_LOGGER, DOMAIN, self.hass, SCAN_INTERVAL, GROUP_NAME_ALL_PP_ASSETS) pp_name = 'xxx' config = { "icon": "mdi:cancel", } self.pp = PowerPool(self.hass, name=pp_name, config=config) component.add_entities([self.pp], update_before_add=True) self.asset1 = EnergyAsset(name='asset1', lat=10, lon=90, schedule=[1, 2, 3, 4, 5], max_flex=[1, 1, 1, 1, 1], min_flex=[1, 1, 1, 1, 1], powerpool=pp_name, hass=self.hass, status='installed' ) self.hass.states.set(f"{ENERGY_ASSET_DOMAIN}.asset1", pp_name, self.asset1.state_attributes) self.asset2 = EnergyAsset(name='asset2', lat=11, lon=99, schedule=[11, 22, 33, 44, 55], max_flex=[1.1, 1.1, 1.1, 1.1, 1.1], min_flex=[1.1, 1.1, 1.1, 1.1, 1.1], powerpool=pp_name, hass=self.hass, status='installed' ) self.hass.states.set(f"{ENERGY_ASSET_DOMAIN}.asset2", pp_name, self.asset2.state_attributes)
def test_adds_entities_with_update_befor_add_true_deadlock_protect(self): """Test if call update befor add to state machine. It need to run update inside executor and never call async_add_entities with True """ call = [] component = EntityComponent(_LOGGER, DOMAIN, self.hass) @asyncio.coroutine def async_add_entities_fake(entities, update_befor_add): """Fake add_entities_call.""" call.append(update_befor_add) component._platforms['core'].async_add_entities = \ async_add_entities_fake ent = EntityTest() ent.update = Mock(spec_set=True) component.add_entities([ent], True) assert ent.update.called assert len(call) == 1 assert not call[0]
def setup(hass, config): """Set up is called when Home Assistant is loading our component.""" dominos = Dominos(hass, config) component = EntityComponent(_LOGGER, DOMAIN, hass) hass.data[DOMAIN] = {} entities = [] conf = config[DOMAIN] hass.services.register(DOMAIN, 'order', dominos.handle_order) if conf.get(ATTR_SHOW_MENU): hass.http.register_view(DominosProductListView(dominos)) for order_info in conf.get(ATTR_ORDERS): order = DominosOrder(order_info, dominos) entities.append(order) if entities: component.add_entities(entities) # Return boolean to indicate that initialization was successfully. return True
def setup(hass, config): host = config[DOMAIN].get(CONF_HOST) password = config[DOMAIN].get(CONF_PASSWORD) opensprinkler = Opensprinkler(host, password) stationIndexes = config[DOMAIN].get(CONF_STATIONS) hass.data[DOMAIN] = { DOMAIN: opensprinkler, CONF_CONFIG: { CONF_STATIONS: stationIndexes, CONF_PROGRAMS: config[DOMAIN].get(CONF_PROGRAMS), }, } component = EntityComponent(_LOGGER, 'input_number', hass) entities = [] for station in opensprinkler.stations(): if len(stationIndexes) == 0 or (station.index in stationIndexes): object_id = '{}_timer'.format(slugify(station.name)) name = station.name minimum = 1 maximum = 10 initial = 1 step = 1 unit = 'minutes' inputNumber = InputNumber(object_id, name, initial, minimum, maximum, step, None, unit, 'slider') entities.append(inputNumber) component.add_entities(entities) load_platform(hass, 'binary_sensor', DOMAIN) load_platform(hass, 'scene', DOMAIN) load_platform(hass, 'switch', DOMAIN) return True
def test_polling_updates_entities_with_exception(self): """Test the updated entities that not break with an exception.""" component = EntityComponent(_LOGGER, DOMAIN, self.hass, timedelta(seconds=20)) update_ok = [] update_err = [] def update_mock(): """Mock normal update.""" update_ok.append(None) def update_mock_err(): """Mock error update.""" update_err.append(None) raise AssertionError("Fake error update") ent1 = MockEntity(should_poll=True) ent1.update = update_mock_err ent2 = MockEntity(should_poll=True) ent2.update = update_mock ent3 = MockEntity(should_poll=True) ent3.update = update_mock ent4 = MockEntity(should_poll=True) ent4.update = update_mock component.add_entities([ent1, ent2, ent3, ent4]) update_ok.clear() update_err.clear() fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20)) self.hass.block_till_done() assert len(update_ok) == 3 assert len(update_err) == 1
async def test_update_state_adds_entities(hass): """Test if updating poll entities cause an entity to be added works.""" component = EntityComponent(_LOGGER, DOMAIN, hass) ent1 = MockEntity() ent2 = MockEntity(should_poll=True) await component.async_add_entities([ent2]) assert len(hass.states.async_entity_ids()) == 1 ent2.update = lambda *_: component.add_entities([ent1]) async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL) await hass.async_block_till_done() assert len(hass.states.async_entity_ids()) == 2
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Plant component.""" _LOGGER.info( "__init__ setup_platform 'sensor' start for %s with config %s.", DOMAIN, config) if config.get(CONF_PLANT_ID) is None: return True if not hasattr(hass.data[DOMAIN], ATTR_FLOWER_CARE_DATA): hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA] = {} params = {} sensors = config.get(CONF_SENSORS) if not (sensors is None): params[CONF_SENSORS] = sensors else: params[CONF_SENSORS] = dict() plant_key = config.get(CONF_PLANT_ID).replace(" ", "_") app_api = hass.data[DOMAIN][SERVICE_API] if not (app_api is None): if not hasattr(hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA], plant_key): flower_info = app_api.retrieve_flower_details( config.get(CONF_PLANT_ID)) _LOGGER.debug( "__init__ setup_platform 'sensor' start for %s. Retrieved Flower: %s", DOMAIN, flower_info) if not (flower_info is None): hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA][ plant_key] = flower_info else: flower_info = hass.data[DOMAIN][ATTR_FLOWER_CARE_DATA][plant_key] _LOGGER.debug( "__init__ setup_platform 'sensor' start for %s. Reused Flower: %s", DOMAIN, flower_info) if not (flower_info is None): params[ATTR_RANGES] = flower_info[API_PARAMETER] params[CONF_MIN_TEMPERATURE] = flower_info[API_PARAMETER][ API_PARAMETER_MIN_TEMP] params[CONF_MAX_TEMPERATURE] = flower_info[API_PARAMETER][ API_PARAMETER_MAX_TEMP] params[CONF_MIN_MOISTURE] = flower_info[API_PARAMETER][ API_PARAMETER_MIN_SOIL_MOIST] params[CONF_MAX_MOISTURE] = flower_info[API_PARAMETER][ API_PARAMETER_MAX_SOIL_MOIST] params[CONF_MIN_CONDUCTIVITY] = flower_info[API_PARAMETER][ API_PARAMETER_MIN_SOIL_EC] params[CONF_MAX_CONDUCTIVITY] = flower_info[API_PARAMETER][ API_PARAMETER_MAX_SOIL_EC] params[CONF_MIN_BRIGHTNESS] = flower_info[API_PARAMETER][ API_PARAMETER_MIN_LIGHT_LUX] params[CONF_MAX_BRIGHTNESS] = flower_info[API_PARAMETER][ API_PARAMETER_MAX_LIGHT_LUX] params[ATTR_BASIC] = flower_info[ATTR_BASIC] params[ATTR_MAINTENANCE] = flower_info[ATTR_MAINTENANCE] params[ATTR_IMAGE] = flower_info[ATTR_IMAGE] # if not (sensors is None): component = EntityComponent(_LOGGER, DOMAIN_PLANT, hass) entities = [] name = config.get(CONF_NAME) entity = Plant(name, params) entities.append(entity) component.add_entities(entities) _LOGGER.debug( "__init__ setup_platform 'sensor' %s in platform %s. Component added with %s.", name, DOMAIN, params) _LOGGER.info("__init__ setup_platform 'sensor' done for %s.", DOMAIN) return True
def setup(hass, config): """Set up the Wink component.""" if hass.data.get(DOMAIN) is None: hass.data[DOMAIN] = { "unique_ids": [], "entities": {}, "oauth": {}, "configuring": {}, "pubnub": None, "configurator": False, } if config.get(DOMAIN) is not None: client_id = config[DOMAIN].get(CONF_CLIENT_ID) client_secret = config[DOMAIN].get(CONF_CLIENT_SECRET) email = config[DOMAIN].get(CONF_EMAIL) password = config[DOMAIN].get(CONF_PASSWORD) local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL) else: client_id = None client_secret = None email = None password = None local_control = None hass.data[DOMAIN]["configurator"] = True if None not in [client_id, client_secret]: _LOGGER.info("Using legacy OAuth authentication") if not local_control: pywink.disable_local_control() hass.data[DOMAIN]["oauth"][CONF_CLIENT_ID] = client_id hass.data[DOMAIN]["oauth"][CONF_CLIENT_SECRET] = client_secret hass.data[DOMAIN]["oauth"]["email"] = email hass.data[DOMAIN]["oauth"]["password"] = password pywink.legacy_set_wink_credentials(email, password, client_id, client_secret) else: _LOGGER.info("Using OAuth authentication") if not local_control: pywink.disable_local_control() config_path = hass.config.path(WINK_CONFIG_FILE) if os.path.isfile(config_path): config_file = load_json(config_path) if config_file == DEFAULT_CONFIG: _request_app_setup(hass, config) return True # else move on because the user modified the file else: save_json(config_path, DEFAULT_CONFIG) _request_app_setup(hass, config) return True if DOMAIN in hass.data[DOMAIN]["configuring"]: _configurator = hass.data[DOMAIN]["configuring"] hass.components.configurator.request_done( _configurator.pop(DOMAIN)) # Using oauth access_token = config_file.get(ATTR_ACCESS_TOKEN) refresh_token = config_file.get(ATTR_REFRESH_TOKEN) # This will be called after authorizing Home-Assistant if None not in (access_token, refresh_token): pywink.set_wink_credentials( config_file.get(CONF_CLIENT_ID), config_file.get(CONF_CLIENT_SECRET), access_token=access_token, refresh_token=refresh_token, ) # This is called to create the redirect so the user can Authorize # Home . else: redirect_uri = f"{get_url(hass)}{WINK_AUTH_CALLBACK_PATH}" wink_auth_start_url = pywink.get_authorization_url( config_file.get(CONF_CLIENT_ID), redirect_uri) hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url) hass.http.register_view( WinkAuthCallbackView(config, config_file, pywink.request_token)) _request_oauth_completion(hass, config) return True pywink.set_user_agent(USER_AGENT) sub_details = pywink.get_subscription_details() hass.data[DOMAIN]["pubnub"] = PubNubSubscriptionHandler( sub_details[0], origin=sub_details[1]) def _subscribe(): hass.data[DOMAIN]["pubnub"].subscribe() # Call subscribe after the user sets up wink via the configurator # All other methods will complete setup before # EVENT_HOMEASSISTANT_START is called meaning they # will call subscribe via the method below. (start_subscription) if hass.data[DOMAIN]["configurator"]: _subscribe() def keep_alive_call(event_time): """Call the Wink API endpoints to keep PubNub working.""" _LOGGER.info("Polling the Wink API to keep PubNub updates flowing") pywink.set_user_agent(str(int(time.time()))) _temp_response = pywink.get_user() _LOGGER.debug(str(json.dumps(_temp_response))) time.sleep(1) pywink.set_user_agent(USER_AGENT) _temp_response = pywink.wink_api_fetch() _LOGGER.debug("%s", _temp_response) _temp_response = pywink.post_session() _LOGGER.debug("%s", _temp_response) # Call the Wink API every hour to keep PubNub updates flowing track_time_interval(hass, keep_alive_call, timedelta(minutes=60)) def start_subscription(event): """Start the PubNub subscription.""" _subscribe() hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription) def stop_subscription(event): """Stop the PubNub subscription.""" hass.data[DOMAIN]["pubnub"].unsubscribe() hass.data[DOMAIN]["pubnub"] = None hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription) def save_credentials(event): """Save currently set OAuth credentials.""" if hass.data[DOMAIN]["oauth"].get("email") is None: config_path = hass.config.path(WINK_CONFIG_FILE) _config = pywink.get_current_oauth_credentials() save_json(config_path, _config) hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials) # Save the users potentially updated oauth credentials at a regular # interval to prevent them from being expired after a HA reboot. track_time_interval(hass, save_credentials, timedelta(minutes=60)) def force_update(call): """Force all devices to poll the Wink API.""" _LOGGER.info("Refreshing Wink states from API") for entity_list in hass.data[DOMAIN]["entities"].values(): # Throttle the calls to Wink API for entity in entity_list: time.sleep(1) entity.schedule_update_ha_state(True) hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update) def pull_new_devices(call): """Pull new devices added to users Wink account since startup.""" _LOGGER.info("Getting new devices from Wink API") for _component in WINK_COMPONENTS: discovery.load_platform(hass, _component, DOMAIN, {}, config) hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices) def set_pairing_mode(call): """Put the hub in provided pairing mode.""" hub_name = call.data.get("hub_name") pairing_mode = call.data.get("pairing_mode") kidde_code = call.data.get("kidde_radio_code") for hub in WINK_HUBS: if hub.name() == hub_name: hub.pair_new_device(pairing_mode, kidde_radio_code=kidde_code) def rename_device(call): """Set specified device's name.""" # This should only be called on one device at a time. found_device = None entity_id = call.data.get("entity_id")[0] all_devices = [] for list_of_devices in hass.data[DOMAIN]["entities"].values(): all_devices += list_of_devices for device in all_devices: if device.entity_id == entity_id: found_device = device if found_device is not None: name = call.data.get("name") found_device.wink.set_name(name) hass.services.register(DOMAIN, SERVICE_RENAME_DEVICE, rename_device, schema=RENAME_DEVICE_SCHEMA) def delete_device(call): """Delete specified device.""" # This should only be called on one device at a time. found_device = None entity_id = call.data.get("entity_id")[0] all_devices = [] for list_of_devices in hass.data[DOMAIN]["entities"].values(): all_devices += list_of_devices for device in all_devices: if device.entity_id == entity_id: found_device = device if found_device is not None: found_device.wink.remove_device() hass.services.register(DOMAIN, SERVICE_DELETE_DEVICE, delete_device, schema=DELETE_DEVICE_SCHEMA) hubs = pywink.get_hubs() for hub in hubs: if hub.device_manufacturer() == "wink": WINK_HUBS.append(hub) if WINK_HUBS: hass.services.register( DOMAIN, SERVICE_SET_PAIRING_MODE, set_pairing_mode, schema=SET_PAIRING_MODE_SCHEMA, ) def nimbus_service_handle(service): """Handle nimbus services.""" entity_id = service.data.get("entity_id")[0] _all_dials = [] for sensor in hass.data[DOMAIN]["entities"]["sensor"]: if isinstance(sensor, WinkNimbusDialDevice): _all_dials.append(sensor) for _dial in _all_dials: if _dial.entity_id == entity_id: if service.service == SERVICE_SET_DIAL_CONFIG: _dial.set_configuration(**service.data) if service.service == SERVICE_SET_DIAL_STATE: _dial.wink.set_state(service.data.get("value"), service.data.get("labels")) def siren_service_handle(service): """Handle siren services.""" entity_ids = service.data.get("entity_id") all_sirens = [] for switch in hass.data[DOMAIN]["entities"]["switch"]: if isinstance(switch, WinkSirenDevice): all_sirens.append(switch) sirens_to_set = [] if entity_ids is None: sirens_to_set = all_sirens else: for siren in all_sirens: if siren.entity_id in entity_ids: sirens_to_set.append(siren) for siren in sirens_to_set: _man = siren.wink.device_manufacturer() if (service.service != SERVICE_SET_AUTO_SHUTOFF and service.service != SERVICE_ENABLE_SIREN and _man not in ("dome", "wink")): _LOGGER.error("Service only valid for Dome or Wink sirens") return if service.service == SERVICE_ENABLE_SIREN: siren.wink.set_state(service.data.get(ATTR_ENABLED)) elif service.service == SERVICE_SET_AUTO_SHUTOFF: siren.wink.set_auto_shutoff( service.data.get(ATTR_AUTO_SHUTOFF)) elif service.service == SERVICE_SET_CHIME_VOLUME: siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME)) elif service.service == SERVICE_SET_SIREN_VOLUME: siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME)) elif service.service == SERVICE_SET_SIREN_TONE: siren.wink.set_siren_sound(service.data.get(ATTR_TONE)) elif service.service == SERVICE_ENABLE_CHIME: siren.wink.set_chime(service.data.get(ATTR_TONE)) elif service.service == SERVICE_SIREN_STROBE_ENABLED: siren.wink.set_siren_strobe_enabled( service.data.get(ATTR_ENABLED)) elif service.service == SERVICE_CHIME_STROBE_ENABLED: siren.wink.set_chime_strobe_enabled( service.data.get(ATTR_ENABLED)) # Load components for the devices in Wink that we support for wink_component in WINK_COMPONENTS: hass.data[DOMAIN]["entities"][wink_component] = [] discovery.load_platform(hass, wink_component, DOMAIN, {}, config) component = EntityComponent(_LOGGER, DOMAIN, hass) sirens = [] has_dome_or_wink_siren = False for siren in pywink.get_sirens(): _man = siren.device_manufacturer() if _man in ("dome", "wink"): has_dome_or_wink_siren = True _id = siren.object_id() + siren.name() if _id not in hass.data[DOMAIN]["unique_ids"]: sirens.append(WinkSirenDevice(siren, hass)) if sirens: hass.services.register( DOMAIN, SERVICE_SET_AUTO_SHUTOFF, siren_service_handle, schema=SET_AUTO_SHUTOFF_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_ENABLE_SIREN, siren_service_handle, schema=ENABLED_SIREN_SCHEMA, ) if has_dome_or_wink_siren: hass.services.register( DOMAIN, SERVICE_SET_SIREN_TONE, siren_service_handle, schema=SET_SIREN_TONE_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_ENABLE_CHIME, siren_service_handle, schema=SET_CHIME_MODE_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_SIREN_VOLUME, siren_service_handle, schema=SET_VOLUME_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_CHIME_VOLUME, siren_service_handle, schema=SET_VOLUME_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SIREN_STROBE_ENABLED, siren_service_handle, schema=SET_STROBE_ENABLED_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_CHIME_STROBE_ENABLED, siren_service_handle, schema=SET_STROBE_ENABLED_SCHEMA, ) component.add_entities(sirens) nimbi = [] dials = {} all_nimbi = pywink.get_cloud_clocks() all_dials = [] for nimbus in all_nimbi: if nimbus.object_type() == "cloud_clock": nimbi.append(nimbus) dials[nimbus.object_id()] = [] for nimbus in all_nimbi: if nimbus.object_type() == "dial": dials[nimbus.parent_id()].append(nimbus) for nimbus in nimbi: for dial in dials[nimbus.object_id()]: all_dials.append(WinkNimbusDialDevice(nimbus, dial, hass)) if nimbi: hass.services.register( DOMAIN, SERVICE_SET_DIAL_CONFIG, nimbus_service_handle, schema=DIAL_CONFIG_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_DIAL_STATE, nimbus_service_handle, schema=DIAL_STATE_SCHEMA, ) component.add_entities(all_dials) return True
def setup(hass, config): """Setup the Homematic component.""" from pyhomematic import HMConnection component = EntityComponent(_LOGGER, DOMAIN, hass) hass.data[DATA_DELAY] = config[DOMAIN].get(CONF_DELAY) hass.data[DATA_DEVINIT] = {} hass.data[DATA_STORE] = [] # create hosts list for pyhomematic remotes = {} hosts = {} for rname, rconfig in config[DOMAIN][CONF_HOSTS].items(): server = rconfig.get(CONF_IP) remotes[rname] = {} remotes[rname][CONF_IP] = server remotes[rname][CONF_PORT] = rconfig.get(CONF_PORT) remotes[rname][CONF_RESOLVENAMES] = rconfig.get(CONF_RESOLVENAMES) remotes[rname][CONF_USERNAME] = rconfig.get(CONF_USERNAME) remotes[rname][CONF_PASSWORD] = rconfig.get(CONF_PASSWORD) if server not in hosts or rconfig.get(CONF_PRIMARY): hosts[server] = { CONF_VARIABLES: rconfig.get(CONF_VARIABLES), CONF_NAME: rname, } hass.data[DATA_DEVINIT][rname] = rconfig.get(CONF_DEVICES) # Create server thread bound_system_callback = partial(_system_callback_handler, hass, config) hass.data[DATA_HOMEMATIC] = HMConnection( local=config[DOMAIN].get(CONF_LOCAL_IP), localport=config[DOMAIN].get(CONF_LOCAL_PORT), remotes=remotes, systemcallback=bound_system_callback, interface_id="homeassistant") # Start server thread, connect to peer, initialize to receive events hass.data[DATA_HOMEMATIC].start() # Stops server when Homeassistant is shutting down hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, hass.data[DATA_HOMEMATIC].stop) hass.config.components.append(DOMAIN) # init homematic hubs hub_entities = [] for _, hub_data in hosts.items(): hub_entities.append( HMHub(hass, component, hub_data[CONF_NAME], hub_data[CONF_VARIABLES])) component.add_entities(hub_entities) # regeister homematic services descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def _hm_service_virtualkey(service): """Service handle virtualkey services.""" address = service.data.get(ATTR_ADDRESS) channel = service.data.get(ATTR_CHANNEL) param = service.data.get(ATTR_PARAM) # device not found hmdevice = _device_from_servicecall(hass, service) if hmdevice is None: _LOGGER.error("%s not found for service virtualkey!", address) return # if param exists for this device if param not in hmdevice.ACTIONNODE: _LOGGER.error("%s not datapoint in hm device %s", param, address) return # channel exists? if channel not in hmdevice.ACTIONNODE[param]: _LOGGER.error("%i is not a channel in hm device %s", channel, address) return # call key hmdevice.actionNodeData(param, True, channel) hass.services.register(DOMAIN, SERVICE_VIRTUALKEY, _hm_service_virtualkey, descriptions[DOMAIN][SERVICE_VIRTUALKEY], schema=SCHEMA_SERVICE_VIRTUALKEY) def _service_handle_value(service): """Set value on homematic variable object.""" variable_list = component.extract_from_service(service) value = service.data[ATTR_VALUE] for hm_variable in variable_list: if isinstance(hm_variable, HMVariable): hm_variable.hm_set(value) hass.services.register(DOMAIN, SERVICE_SET_VAR_VALUE, _service_handle_value, descriptions[DOMAIN][SERVICE_SET_VAR_VALUE], schema=SCHEMA_SERVICE_SET_VAR_VALUE) def _service_handle_reconnect(service): """Reconnect to all homematic hubs.""" hass.data[DATA_HOMEMATIC].reconnect() hass.services.register(DOMAIN, SERVICE_RECONNECT, _service_handle_reconnect, descriptions[DOMAIN][SERVICE_RECONNECT], schema=SCHEMA_SERVICE_RECONNECT) def _service_handle_device(service): """Service handle set_dev_value services.""" address = service.data.get(ATTR_ADDRESS) channel = service.data.get(ATTR_CHANNEL) param = service.data.get(ATTR_PARAM) value = service.data.get(ATTR_VALUE) # device not found hmdevice = _device_from_servicecall(hass, service) if hmdevice is None: _LOGGER.error("%s not found!", address) return # call key hmdevice.setValue(param, value, channel) hass.services.register(DOMAIN, SERVICE_SET_DEV_VALUE, _service_handle_device, descriptions[DOMAIN][SERVICE_SET_DEV_VALUE], schema=SCHEMA_SERVICE_SET_DEV_VALUE) return True
def setup(hass, config): """Set up variables.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] items = config.get(DOMAIN) if items is not None: for variable_id, variable_config in items.items(): if not variable_config: variable_config = {} name = variable_config.get(CONF_NAME) default_temp = variable_config.get(ATTR_DEFAULT_TEMP) entities.append(TemperatureControl(variable_id, name, default_temp)) def get_temperature_service(call): """Handle calls to the set_variable service.""" entity_id = ENTITY_ID_FORMAT.format(call.data.get(ATTR_CONTROLLER)) entity = component.get_entity(entity_id) if entity: return entity.get_temperature(call.data.get(CONF_TIME_STEP)) else: _LOGGER.warning("Failed to set unknown variable: %s", entity_id) def set_period_service(call): """Handle calls to the set_variable service.""" entity_id = ENTITY_ID_FORMAT.format(call.data.get(CONF_NAME)) entity = component.get_entity(entity_id) _LOGGER.warning( f'Start updating (set_period_service) period on {entity_id}') if entity: entity.set_period( call.data.get(CONF_PERIOD_ID), call.data.get(CONF_TIME_START), call.data.get(CONF_TIME_STOP), call.data.get(CONF_PERIOD_TEMP), call.data.get(CONF_DAYS), ) else: _LOGGER.warning("Failed to set unknown variable: %s", entity_id) hass.services.register( DOMAIN, SERVICE_GET_TEMPERATURE, get_temperature_service, schema=SERVICE_GET_TEMPERATURE_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_PERIOD, set_period_service, schema=SERVICE_SET_PERIOD_SCHEMA, ) component.add_entities(entities) return True
def setup(hass, config): """Setup zigate platform.""" port = config[DOMAIN].get(CONF_PORT) host = config[DOMAIN].get(CONF_HOST) gpio = config[DOMAIN].get('gpio', False) enable_led = config[DOMAIN].get('enable_led', True) polling = config[DOMAIN].get('polling', True) channel = config[DOMAIN].get('channel') scan_interval = datetime.timedelta( seconds=config[DOMAIN].get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)) admin_panel = config[DOMAIN].get('admin_panel', True) persistent_file = os.path.join(hass.config.config_dir, 'zigate.json') _LOGGER.debug('Port : %s', port) _LOGGER.debug('Host : %s', host) _LOGGER.debug('GPIO : %s', gpio) _LOGGER.debug('Led : %s', enable_led) _LOGGER.debug('Channel : %s', channel) _LOGGER.debug('Scan interval : %s', scan_interval) myzigate = zigate.connect(port=port, host=host, path=persistent_file, auto_start=False, gpio=gpio) _LOGGER.debug('ZiGate object created %s', myzigate) hass.data[DOMAIN] = myzigate hass.data[DATA_ZIGATE_DEVICES] = {} hass.data[DATA_ZIGATE_ATTRS] = {} component = EntityComponent(_LOGGER, DOMAIN, hass, scan_interval) # component.setup(config) entity = ZiGateComponentEntity(myzigate) hass.data[DATA_ZIGATE_DEVICES]['zigate'] = entity component.add_entities([entity]) def device_added(**kwargs): device = kwargs['device'] _LOGGER.debug('Add device {}'.format(device)) ieee = device.ieee if ieee not in hass.data[DATA_ZIGATE_DEVICES]: hass.data[DATA_ZIGATE_DEVICES][ieee] = None # reserve entity = ZiGateDeviceEntity(hass, device, polling) hass.data[DATA_ZIGATE_DEVICES][ieee] = entity component.add_entities([entity]) if 'signal' in kwargs: hass.components.persistent_notification.create( ('A new ZiGate device "{}"' ' has been added !').format(device), title='ZiGate') def device_removed(**kwargs): # component.async_remove_entity device = kwargs['device'] ieee = device.ieee hass.components.persistent_notification.create( 'The ZiGate device {}({}) is gone.'.format(device.ieee, device.addr), title='ZiGate') entity = hass.data[DATA_ZIGATE_DEVICES][ieee] component.async_remove_entity(entity.entity_id) del hass.data[DATA_ZIGATE_DEVICES][ieee] def device_need_discovery(**kwargs): device = kwargs['device'] hass.components.persistent_notification.create( ('The ZiGate device {}({}) needs to be discovered' ' (missing important' ' information)').format(device.ieee, device.addr), title='ZiGate') zigate.dispatcher.connect(device_added, zigate.ZIGATE_DEVICE_ADDED, weak=False) zigate.dispatcher.connect(device_removed, zigate.ZIGATE_DEVICE_REMOVED, weak=False) zigate.dispatcher.connect(device_need_discovery, zigate.ZIGATE_DEVICE_NEED_DISCOVERY, weak=False) def attribute_updated(**kwargs): device = kwargs['device'] ieee = device.ieee attribute = kwargs['attribute'] _LOGGER.debug('Update attribute for device {} {}'.format( device, attribute)) entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee) event_data = attribute.copy() if type(event_data.get('type')) == type: event_data['type'] = event_data['type'].__name__ event_data['ieee'] = device.ieee event_data['addr'] = device.addr event_data['device_type'] = device.get_property_value('type') if entity: event_data['entity_id'] = entity.entity_id hass.bus.fire('zigate.attribute_updated', event_data) zigate.dispatcher.connect(attribute_updated, zigate.ZIGATE_ATTRIBUTE_UPDATED, weak=False) def device_updated(**kwargs): device = kwargs['device'] _LOGGER.debug('Update device {}'.format(device)) ieee = device.ieee entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee) if not entity: _LOGGER.debug('Device not found {}, adding it'.format(device)) device_added(device=device) event_data = {} event_data['ieee'] = device.ieee event_data['addr'] = device.addr event_data['device_type'] = device.get_property_value('type') if entity: event_data['entity_id'] = entity.entity_id hass.bus.fire('zigate.device_updated', event_data) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_DEVICE_UPDATED, weak=False) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_ATTRIBUTE_ADDED, weak=False) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_DEVICE_ADDRESS_CHANGED, weak=False) def zigate_reset(service): myzigate.reset() def permit_join(service): myzigate.permit_join() def zigate_cleanup(service): ''' Remove missing device ''' myzigate.cleanup_devices() def start_zigate(service_event=None): myzigate.autoStart(channel) myzigate.start_auto_save() myzigate.set_led(enable_led) version = myzigate.get_version_text() if version < '3.1a': hass.components.persistent_notification.create( ('Your zigate firmware is outdated, ' 'Please upgrade to 3.1a or later !'), title='ZiGate') # first load for device in myzigate.devices: device_added(device=device) for platform in SUPPORTED_PLATFORMS: load_platform(hass, platform, DOMAIN, {}, config) hass.bus.fire('zigate.started') def stop_zigate(service=None): myzigate.save_state() myzigate.close() hass.bus.fire('zigate.stopped') def refresh_devices_list(service): myzigate.get_devices_list() def generate_templates(service): myzigate.generate_templates(hass.config.config_dir) def _get_addr_from_service_request(service): entity_id = service.data.get(ATTR_ENTITY_ID) ieee = service.data.get(IEEE) addr = service.data.get(ADDR) if entity_id: entity = component.get_entity(entity_id) if entity: addr = entity._device.addr elif ieee: device = myzigate.get_device_from_ieee(ieee) if device: addr = device.addr return addr def _to_int(value): ''' convert str to int ''' if 'x' in value: return int(value, 16) return int(value) def refresh_device(service): full = service.data.get('full', False) addr = _get_addr_from_service_request(service) if addr: myzigate.refresh_device(addr, full=full) else: for device in myzigate.devices: device.refresh_device(full=full) def discover_device(service): addr = _get_addr_from_service_request(service) if addr: myzigate.discover_device(addr, True) def network_scan(service): myzigate.start_network_scan() def raw_command(service): cmd = _to_int(service.data.get('cmd')) data = service.data.get('data', '') myzigate.send_data(cmd, data) def identify_device(service): addr = _get_addr_from_service_request(service) myzigate.identify_device(addr) def remove_device(service): addr = _get_addr_from_service_request(service) myzigate.remove_device(addr) def initiate_touchlink(service): myzigate.initiate_touchlink() def touchlink_factory_reset(service): myzigate.touchlink_factory_reset() def read_attribute(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) cluster = _to_int(service.data.get('cluster')) attribute_id = _to_int(service.data.get('attribute_id')) manufacturer_code = _to_int(service.data.get('manufacturer_code', '0')) myzigate.read_attribute_request(addr, endpoint, cluster, attribute_id, manufacturer_code=manufacturer_code) def write_attribute(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) cluster = _to_int(service.data.get('cluster')) attribute_id = _to_int(service.data.get('attribute_id')) attribute_type = _to_int(service.data.get('attribute_type')) value = _to_int(service.data.get('value')) attributes = [(attribute_id, attribute_type, value)] manufacturer_code = _to_int(service.data.get('manufacturer_code', '0')) myzigate.write_attribute_request(addr, endpoint, cluster, attributes, manufacturer_code=manufacturer_code) def add_group(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) groupaddr = service.data.get('group_addr') myzigate.add_group(addr, endpoint, groupaddr) def remove_group(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) groupaddr = service.data.get('group_addr') myzigate.remove_group(addr, endpoint, groupaddr) def get_group_membership(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) myzigate.get_group_membership(addr, endpoint) def action_onoff(service): addr = _get_addr_from_service_request(service) onoff = _to_int(service.data.get('onoff')) endpoint = _to_int(service.data.get('endpoint', '0')) ontime = _to_int(service.data.get('on_time', '0')) offtime = _to_int(service.data.get('off_time', '0')) effect = _to_int(service.data.get('effect', '0')) gradient = _to_int(service.data.get('gradient', '0')) myzigate.action_onoff(addr, endpoint, onoff, ontime, offtime, effect, gradient) def build_network_table(service): table = myzigate.build_neighbours_table( service.data.get('force', False)) _LOGGER.debug('Neighbours table {}'.format(table)) def ota_load_image(service): ota_image_path = service.data.get('imagepath') myzigate.ota_load_image(ota_image_path) def ota_image_notify(service): addr = _get_addr_from_service_request(service) destination_endpoint = _to_int( service.data.get('destination_endpoint', '1')) payload_type = _to_int(service.data.get('payload_type', '0')) myzigate.ota_image_notify(addr, destination_endpoint, payload_type) def get_ota_status(service): myzigate.get_ota_status() def view_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) myzigate.view_scene(addr, endpoint, groupaddr, scene) def add_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) name = service.data.get('scene_name') transition = _to_int(service.data.get('transition', '0')) myzigate.add_scene(addr, endpoint, groupaddr, scene, name, transition) def remove_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene', -1)) if scene == -1: scene = None myzigate.remove_scene(addr, endpoint, groupaddr, scene) def store_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) myzigate.store_scene(addr, endpoint, groupaddr, scene) def recall_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) myzigate.recall_scene(addr, endpoint, groupaddr, scene) def scene_membership_request(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') myzigate.scene_membership_request(addr, endpoint, groupaddr) def copy_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) fromgroupaddr = service.data.get('from_group_addr') fromscene = _to_int(service.data.get('from_scene')) togroupaddr = service.data.get('to_group_addr') toscene = _to_int(service.data.get('to_scene')) myzigate.copy_scene(addr, endpoint, fromgroupaddr, fromscene, togroupaddr, toscene) def ias_warning(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) mode = service.data.get('mode', 'burglar') strobe = service.data.get('strobe', True) level = service.data.get('level', 'low') duration = service.data.get('duration', 60) strobe_cycle = service.data.get('strobe_cycle', 10) strobe_level = service.data.get('strobe_level', 'low') myzigate.action_ias_warning(addr, endpoint, mode, strobe, level, duration, strobe_cycle, strobe_level) def ias_squawk(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) mode = service.data.get('mode', 'armed') strobe = service.data.get('strobe', True) level = service.data.get('level', 'low') myzigate.action_ias_squawk(addr, endpoint, mode, strobe, level) def upgrade_firmware(service): from zigate.flasher import flash from zigate.firmware import download_latest port = myzigate._port pizigate = False if isinstance(myzigate, zigate.ZiGateGPIO): pizigate = True if myzigate._started and not pizigate: msg = 'You should stop zigate first using service zigate.stop_zigate and put zigate in download mode.' hass.components.persistent_notification.create(msg, title='ZiGate') return if pizigate: stop_zigate() myzigate.set_bootloader_mode() backup_filename = 'zigate_backup_{:%Y%m%d%H%M%S}.bin'.format( datetime.datetime.now()) backup_filename = os.path.join(hass.config.config_dir, backup_filename) flash(port, save=backup_filename) msg = 'ZiGate backup created {}'.format(backup_filename) hass.components.persistent_notification.create(msg, title='ZiGate') firmware_path = service.data.get('path') if not firmware_path: firmware_path = download_latest() flash(port, write=firmware_path) msg = 'ZiGate flashed with {}'.format(firmware_path) hass.components.persistent_notification.create(msg, title='ZiGate') myzigate._version = None if pizigate: myzigate.set_running_mode() start_zigate() else: msg = 'Now you have to unplug/replug the ZiGate USB key and then call service zigate.start_zigate' hass.components.persistent_notification.create(msg, title='ZiGate') hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zigate) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zigate) hass.services.register(DOMAIN, 'refresh_devices_list', refresh_devices_list) hass.services.register(DOMAIN, 'generate_templates', generate_templates) hass.services.register(DOMAIN, 'reset', zigate_reset) hass.services.register(DOMAIN, 'permit_join', permit_join) hass.services.register(DOMAIN, 'start_zigate', start_zigate) hass.services.register(DOMAIN, 'stop_zigate', stop_zigate) hass.services.register(DOMAIN, 'cleanup_devices', zigate_cleanup) hass.services.register(DOMAIN, 'refresh_device', refresh_device, schema=REFRESH_DEVICE_SCHEMA) hass.services.register(DOMAIN, 'discover_device', discover_device, schema=DISCOVER_DEVICE_SCHEMA) hass.services.register(DOMAIN, 'network_scan', network_scan) hass.services.register(DOMAIN, 'raw_command', raw_command, schema=RAW_COMMAND_SCHEMA) hass.services.register(DOMAIN, 'identify_device', identify_device, schema=IDENTIFY_SCHEMA) hass.services.register(DOMAIN, 'remove_device', remove_device, schema=REMOVE_SCHEMA) hass.services.register(DOMAIN, 'initiate_touchlink', initiate_touchlink) hass.services.register(DOMAIN, 'touchlink_factory_reset', touchlink_factory_reset) hass.services.register(DOMAIN, 'read_attribute', read_attribute, schema=READ_ATTRIBUTE_SCHEMA) hass.services.register(DOMAIN, 'write_attribute', write_attribute, schema=WRITE_ATTRIBUTE_SCHEMA) hass.services.register(DOMAIN, 'add_group', add_group, schema=ADD_GROUP_SCHEMA) hass.services.register(DOMAIN, 'get_group_membership', get_group_membership, schema=GET_GROUP_MEMBERSHIP_SCHEMA) hass.services.register(DOMAIN, 'remove_group', remove_group, schema=REMOVE_GROUP_SCHEMA) hass.services.register(DOMAIN, 'action_onoff', action_onoff, schema=ACTION_ONOFF_SCHEMA) hass.services.register(DOMAIN, 'build_network_table', build_network_table, schema=BUILD_NETWORK_TABLE_SCHEMA) hass.services.register(DOMAIN, 'ias_warning', ias_warning, schema=ACTION_IAS_WARNING_SCHEMA) hass.services.register(DOMAIN, 'ias_squawk', ias_squawk, schema=ACTION_IAS_SQUAWK_SCHEMA) hass.services.register(DOMAIN, 'ota_load_image', ota_load_image, schema=OTA_LOAD_IMAGE_SCHEMA) hass.services.register(DOMAIN, 'ota_image_notify', ota_image_notify, schema=OTA_IMAGE_NOTIFY_SCHEMA) hass.services.register(DOMAIN, 'ota_get_status', get_ota_status) hass.services.register(DOMAIN, 'view_scene', view_scene, schema=VIEW_SCENE_SCHEMA) hass.services.register(DOMAIN, 'add_scene', add_scene, schema=ADD_SCENE_SCHEMA) hass.services.register(DOMAIN, 'remove_scene', remove_scene, schema=REMOVE_SCENE_SCHEMA) hass.services.register(DOMAIN, 'store_scene', store_scene, schema=STORE_SCENE_SCHEMA) hass.services.register(DOMAIN, 'recall_scene', recall_scene, schema=RECALL_SCENE_SCHEMA) hass.services.register(DOMAIN, 'scene_membership_request', scene_membership_request, schema=SCENE_MEMBERSHIP_REQUEST_SCHEMA) hass.services.register(DOMAIN, 'copy_scene', copy_scene, schema=COPY_SCENE_SCHEMA) hass.services.register(DOMAIN, 'upgrade_firmware', upgrade_firmware) track_time_change(hass, refresh_devices_list, hour=0, minute=0, second=0) if admin_panel: _LOGGER.debug('Start ZiGate Admin Panel on port 9998') myzigate.start_adminpanel(prefix='/zigateproxy') hass.http.register_view(ZiGateAdminPanel()) hass.http.register_view(ZiGateProxy()) custom_panel_config = { "name": "zigateadmin", "embed_iframe": False, "trust_external": False, "html_url": "/zigateadmin.html", } config = {} config["_panel_custom"] = custom_panel_config hass.components.frontend.async_register_built_in_panel( component_name="custom", sidebar_title='Zigate Admin', sidebar_icon='mdi:zigbee', frontend_url_path="zigateadmin", config=config, require_admin=True, ) # hass.async_create_task( # hass.config_entries.flow.async_init( # DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={} # ) # ) return True
class SmartReminders: """Main Smart Reminders Service""" def __init__(self, hass, config): self.hass = hass self.conf = config self.db = SmartReminderDB(config) items = [] try: self.items = self.db.get_all_reminders() except: self.items = [] self.component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] if self.items: for item in self.items: ent = SmartReminderItem(hass, item, self.db) entities.append(ent) if entities: self.component.add_entities(entities) hass.services.register(DOMAIN, "add_task", self.handle_add_task) hass.services.register(DOMAIN, "complete_task", self.handle_complete_task) hass.services.register(DOMAIN, "delete_task", self.handle_delete_task) async def handle_add_task(self, call): """Handle the service call.""" await self.add_task(call.data) async def handle_delete_task(self, call): try: entity_id = call.data.get('id') ent = self.component.get_entity(entity_id) idx = ent._id await self.db.delete_reminder(idx) await self.component.async_remove_entity(entity_id) except Exception as e: logging.error(traceback.format_exc()) async def handle_complete_task(self, call): """Handle completing the task and removing it from entities""" try: entity_id = call.data.get('id') ent = self.component.get_entity(entity_id) idx = ent._id self.db.complete_reminder(idx) if ent.is_repeatable: derp = {ent._repeat_type: ent._repeat_number} due_date = ent._original_due_date + timedelta(**derp) data = { ATTR_TITLE: ent._title, "user": ent._username, ATTR_DUE: due_date, "repeat_type": ent._repeat_type, "repeat_number": ent._repeat_number, "repeatable": True } await self.add_task(data) await self.component.async_remove_entity(entity_id) except Exception as e: logging.error(traceback.format_exc()) async def add_task(self, data): try: new_item = await self.db.add_reminder(data) ent = SmartReminderItem(self.hass, new_item, self.db) await self.component.async_add_entities([ent]) except Exception as e: logging.error(traceback.format_exc())
def setup(hass, config): """Setup zigate platform.""" import zigate port = config[DOMAIN].get(CONF_PORT) host = config[DOMAIN].get(CONF_HOST) gpio = config[DOMAIN].get('gpio', False) enable_led = config[DOMAIN].get('enable_led', True) polling = config[DOMAIN].get('polling', True) channel = config[DOMAIN].get('channel') persistent_file = os.path.join(hass.config.config_dir, 'zigate.json') _LOGGER.debug('Port : %s', port) _LOGGER.debug('Host : %s', host) _LOGGER.debug('GPIO : %s', gpio) _LOGGER.debug('Led : %s', enable_led) _LOGGER.debug('Channel : %s', channel) myzigate = zigate.connect(port=port, host=host, path=persistent_file, auto_start=False, gpio=gpio ) _LOGGER.debug('ZiGate object created %s', myzigate) hass.data[DOMAIN] = myzigate hass.data[DATA_ZIGATE_DEVICES] = {} hass.data[DATA_ZIGATE_ATTRS] = {} component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_ZIGATE) component.setup(config) entity = ZiGateComponentEntity(myzigate) hass.data[DATA_ZIGATE_DEVICES]['zigate'] = entity component.add_entities([entity]) def device_added(**kwargs): device = kwargs['device'] _LOGGER.debug('Add device {}'.format(device)) ieee = device.ieee or device.addr # compatibility if ieee not in hass.data[DATA_ZIGATE_DEVICES]: entity = ZiGateDeviceEntity(hass, device, polling) hass.data[DATA_ZIGATE_DEVICES][ieee] = entity component.add_entities([entity]) if 'signal' in kwargs: hass.components.persistent_notification.create( ('A new ZiGate device "{}"' ' has been added !' ).format(device), title='ZiGate') def device_removed(**kwargs): # component.async_remove_entity device = kwargs['device'] ieee = device.ieee or device.addr # compatibility hass.components.persistent_notification.create( 'The ZiGate device {}({}) is gone.'.format(device.ieee, device.addr), title='ZiGate') entity = hass.data[DATA_ZIGATE_DEVICES][ieee] component.async_remove_entity(entity.entity_id) del hass.data[DATA_ZIGATE_DEVICES][ieee] def device_need_discovery(**kwargs): device = kwargs['device'] hass.components.persistent_notification.create( ('The ZiGate device {}({}) needs to be discovered' ' (missing important' ' information)').format(device.ieee, device.addr), title='ZiGate') zigate.dispatcher.connect(device_added, zigate.ZIGATE_DEVICE_ADDED, weak=False) zigate.dispatcher.connect(device_removed, zigate.ZIGATE_DEVICE_REMOVED, weak=False) zigate.dispatcher.connect(device_need_discovery, zigate.ZIGATE_DEVICE_NEED_DISCOVERY, weak=False) def attribute_updated(**kwargs): device = kwargs['device'] ieee = device.ieee or device.addr # compatibility attribute = kwargs['attribute'] _LOGGER.debug('Update attribute for device {} {}'.format(device, attribute)) entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee) event_data = attribute.copy() if type(event_data.get('type')) == type: event_data['type'] = event_data['type'].__name__ event_data['ieee'] = device.ieee event_data['addr'] = device.addr event_data['device_type'] = device.get_property_value('type') if entity: event_data['entity_id'] = entity.entity_id hass.bus.fire('zigate.attribute_updated', event_data) zigate.dispatcher.connect(attribute_updated, zigate.ZIGATE_ATTRIBUTE_UPDATED, weak=False) def device_updated(**kwargs): device = kwargs['device'] _LOGGER.debug('Update device {}'.format(device)) ieee = device.ieee or device.addr # compatibility entity = hass.data[DATA_ZIGATE_DEVICES].get(ieee) if not entity: _LOGGER.debug('Device not found {}, adding it'.format(device)) device_added(device=device) event_data = {} event_data['ieee'] = device.ieee event_data['addr'] = device.addr event_data['device_type'] = device.get_property_value('type') if entity: event_data['entity_id'] = entity.entity_id hass.bus.fire('zigate.device_updated', event_data) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_DEVICE_UPDATED, weak=False) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_ATTRIBUTE_ADDED, weak=False) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_DEVICE_ADDRESS_CHANGED, weak=False) def zigate_reset(service): myzigate.reset() def permit_join(service): myzigate.permit_join() def zigate_cleanup(service): ''' Remove missing device ''' myzigate.cleanup_devices() def start_zigate(service_event=None): myzigate.autoStart(channel) myzigate.start_auto_save() myzigate.set_led(enable_led) version = myzigate.get_version_text() if version < '3.0f': hass.components.persistent_notification.create( ('Your zigate firmware is outdated, ' 'Please upgrade to 3.0f or later !'), title='ZiGate') # first load for device in myzigate.devices: device_added(device=device) for platform in SUPPORTED_PLATFORMS: load_platform(hass, platform, DOMAIN, {}, config) hass.bus.fire('zigate.started') def stop_zigate(service_event): myzigate.save_state() myzigate.close() hass.bus.fire('zigate.stopped') def refresh_devices_list(service): myzigate.get_devices_list() def generate_templates(service): myzigate.generate_templates(hass.config.config_dir) def _get_addr_from_service_request(service): entity_id = service.data.get(ATTR_ENTITY_ID) ieee = service.data.get(IEEE) addr = service.data.get(ADDR) if entity_id: entity = component.get_entity(entity_id) if entity: addr = entity._device.addr elif ieee: device = myzigate.get_device_from_ieee(ieee) if device: addr = device.addr return addr def _to_int(value): ''' convert str to int ''' if 'x' in value: return int(value, 16) return int(value) def refresh_device(service): addr = _get_addr_from_service_request(service) if addr: myzigate.refresh_device(addr, full=True) else: for device in myzigate.devices: device.refresh_device(full=True) def discover_device(service): addr = _get_addr_from_service_request(service) if addr: myzigate.discover_device(addr, True) def network_scan(service): myzigate.start_network_scan() def raw_command(service): cmd = _to_int(service.data.get('cmd')) data = service.data.get('data', '') myzigate.send_data(cmd, data) def identify_device(service): addr = _get_addr_from_service_request(service) myzigate.identify_device(addr) def remove_device(service): addr = _get_addr_from_service_request(service) myzigate.remove_device(addr) def initiate_touchlink(service): myzigate.initiate_touchlink() def touchlink_factory_reset(service): myzigate.touchlink_factory_reset() def read_attribute(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) cluster = _to_int(service.data.get('cluster')) attribute_id = _to_int(service.data.get('attribute_id')) manufacturer_code = _to_int(service.data.get('manufacturer_code', '0')) myzigate.read_attribute_request(addr, endpoint, cluster, attribute_id, manufacturer_code=manufacturer_code) def write_attribute(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) cluster = _to_int(service.data.get('cluster')) attribute_id = _to_int(service.data.get('attribute_id')) attribute_type = _to_int(service.data.get('attribute_type')) value = _to_int(service.data.get('value')) attributes = [(attribute_id, attribute_type, value)] manufacturer_code = _to_int(service.data.get('manufacturer_code', '0')) myzigate.write_attribute_request(addr, endpoint, cluster, attributes, manufacturer_code=manufacturer_code) def add_group(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) groupaddr = service.data.get('group_addr') myzigate.add_group(addr, endpoint, groupaddr) def remove_group(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) groupaddr = service.data.get('group_addr') myzigate.remove_group(addr, endpoint, groupaddr) def get_group_membership(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint')) myzigate.get_group_membership(addr, endpoint) def action_onoff(service): addr = _get_addr_from_service_request(service) onoff = _to_int(service.data.get('onoff')) endpoint = _to_int(service.data.get('endpoint', '0')) ontime = _to_int(service.data.get('on_time', '0')) offtime = _to_int(service.data.get('off_time', '0')) effect = _to_int(service.data.get('effect', '0')) gradient = _to_int(service.data.get('gradient', '0')) myzigate.action_onoff(addr, endpoint, onoff, ontime, offtime, effect, gradient) def build_network_table(service): table = myzigate.build_neighbours_table(service.data.get('force', False)) _LOGGER.debug('Neighbours table {}'.format(table)) entity = hass.data[DATA_ZIGATE_DEVICES].get('zigate') if entity: entity.network_table = table def ota_load_image(service): ota_image_path = service.data.get('imagepath') myzigate.ota_load_image(ota_image_path) def ota_image_notify(service): addr = _get_addr_from_service_request(service) destination_endpoint = _to_int(service.data.get('destination_endpoint', '1')) payload_type = _to_int(service.data.get('payload_type', '0')) myzigate.ota_image_notify(addr, destination_endpoint, payload_type) def get_ota_status(service): myzigate.get_ota_status() def view_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) myzigate.view_scene(addr, endpoint, groupaddr, scene) def add_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) name = service.data.get('scene_name') transition = _to_int(service.data.get('transition', '0')) myzigate.add_scene(addr, endpoint, groupaddr, scene, name, transition) def remove_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene', -1)) if scene == -1: scene = None myzigate.remove_scene(addr, endpoint, groupaddr, scene) def store_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) myzigate.store_scene(addr, endpoint, groupaddr, scene) def recall_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') scene = _to_int(service.data.get('scene')) myzigate.recall_scene(addr, endpoint, groupaddr, scene) def scene_membership_request(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) groupaddr = service.data.get('group_addr') myzigate.scene_membership_request(addr, endpoint, groupaddr) def copy_scene(service): addr = _get_addr_from_service_request(service) endpoint = _to_int(service.data.get('endpoint', '1')) fromgroupaddr = service.data.get('from_group_addr') fromscene = _to_int(service.data.get('from_scene')) togroupaddr = service.data.get('to_group_addr') toscene = _to_int(service.data.get('to_scene')) myzigate.copy_scene(addr, endpoint, fromgroupaddr, fromscene, togroupaddr, toscene) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zigate) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zigate) hass.services.register(DOMAIN, 'refresh_devices_list', refresh_devices_list) hass.services.register(DOMAIN, 'generate_templates', generate_templates) hass.services.register(DOMAIN, 'reset', zigate_reset) hass.services.register(DOMAIN, 'permit_join', permit_join) hass.services.register(DOMAIN, 'start_zigate', start_zigate) hass.services.register(DOMAIN, 'stop_zigate', stop_zigate) hass.services.register(DOMAIN, 'cleanup_devices', zigate_cleanup) hass.services.register(DOMAIN, 'refresh_device', refresh_device, schema=REFRESH_DEVICE_SCHEMA) hass.services.register(DOMAIN, 'discover_device', discover_device, schema=DISCOVER_DEVICE_SCHEMA) hass.services.register(DOMAIN, 'network_scan', network_scan) hass.services.register(DOMAIN, 'raw_command', raw_command, schema=RAW_COMMAND_SCHEMA) hass.services.register(DOMAIN, 'identify_device', identify_device, schema=IDENTIFY_SCHEMA) hass.services.register(DOMAIN, 'remove_device', remove_device, schema=REMOVE_SCHEMA) hass.services.register(DOMAIN, 'initiate_touchlink', initiate_touchlink) hass.services.register(DOMAIN, 'touchlink_factory_reset', touchlink_factory_reset) hass.services.register(DOMAIN, 'read_attribute', read_attribute, schema=READ_ATTRIBUTE_SCHEMA) hass.services.register(DOMAIN, 'write_attribute', write_attribute, schema=WRITE_ATTRIBUTE_SCHEMA) hass.services.register(DOMAIN, 'add_group', add_group, schema=ADD_GROUP_SCHEMA) hass.services.register(DOMAIN, 'get_group_membership', get_group_membership, schema=GET_GROUP_MEMBERSHIP_SCHEMA) hass.services.register(DOMAIN, 'remove_group', remove_group, schema=REMOVE_GROUP_SCHEMA) hass.services.register(DOMAIN, 'action_onoff', action_onoff, schema=ACTION_ONOFF_SCHEMA) hass.services.register(DOMAIN, 'build_network_table', build_network_table, schema=BUILD_NETWORK_TABLE_SCHEMA) hass.services.register(DOMAIN, 'ota_load_image', ota_load_image, schema=OTA_LOAD_IMAGE_SCHEMA) hass.services.register(DOMAIN, 'ota_image_notify', ota_image_notify, schema=OTA_IMAGE_NOTIFY_SCHEMA) hass.services.register(DOMAIN, 'ota_get_status', get_ota_status) hass.services.register(DOMAIN, 'view_scene', view_scene, schema=VIEW_SCENE_SCHEMA) hass.services.register(DOMAIN, 'add_scene', add_scene, schema=ADD_SCENE_SCHEMA) hass.services.register(DOMAIN, 'remove_scene', remove_scene, schema=REMOVE_SCENE_SCHEMA) hass.services.register(DOMAIN, 'store_scene', store_scene, schema=STORE_SCENE_SCHEMA) hass.services.register(DOMAIN, 'recall_scene', recall_scene, schema=RECALL_SCENE_SCHEMA) hass.services.register(DOMAIN, 'scene_membership_request', scene_membership_request, schema=SCENE_MEMBERSHIP_REQUEST_SCHEMA) hass.services.register(DOMAIN, 'copy_scene', copy_scene, schema=COPY_SCENE_SCHEMA) track_time_change(hass, refresh_devices_list, hour=0, minute=0, second=0) return True
def setup(hass, config): """Setup the Homematic component.""" global HOMEMATIC, HOMEMATIC_LINK_DELAY from pyhomematic import HMConnection component = EntityComponent(_LOGGER, DOMAIN, hass) local_ip = config[DOMAIN].get(CONF_LOCAL_IP) local_port = config[DOMAIN].get(CONF_LOCAL_PORT) remote_ip = config[DOMAIN].get(CONF_REMOTE_IP) remote_port = config[DOMAIN].get(CONF_REMOTE_PORT) resolvenames = config[DOMAIN].get(CONF_RESOLVENAMES) username = config[DOMAIN].get(CONF_USERNAME) password = config[DOMAIN].get(CONF_PASSWORD) HOMEMATIC_LINK_DELAY = config[DOMAIN].get(CONF_DELAY) use_variables = config[DOMAIN].get(CONF_VARIABLES) if remote_ip is None or local_ip is None: _LOGGER.error("Missing remote CCU/Homegear or local address") return False # Create server thread bound_system_callback = partial(_system_callback_handler, hass, config) HOMEMATIC = HMConnection(local=local_ip, localport=local_port, remote=remote_ip, remoteport=remote_port, systemcallback=bound_system_callback, resolvenames=resolvenames, rpcusername=username, rpcpassword=password, interface_id="homeassistant") # Start server thread, connect to peer, initialize to receive events HOMEMATIC.start() # Stops server when Homeassistant is shutting down hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, HOMEMATIC.stop) hass.config.components.append(DOMAIN) # regeister homematic services descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.register(DOMAIN, SERVICE_VIRTUALKEY, _hm_service_virtualkey, descriptions[DOMAIN][SERVICE_VIRTUALKEY], schema=SCHEMA_SERVICE_VIRTUALKEY) entities = [] ## # init HM variable variables = HOMEMATIC.getAllSystemVariables() if use_variables else {} hm_var_store = {} if variables is not None: for key, value in variables.items(): varia = HMVariable(key, value) hm_var_store.update({key: varia}) entities.append(varia) # add homematic entites entities.append(HMHub(hm_var_store, use_variables)) component.add_entities(entities) ## # register set_value service if exists variables if not variables: return True def _service_handle_value(service): """Set value on homematic variable object.""" variable_list = component.extract_from_service(service) value = service.data[ATTR_VALUE] for hm_variable in variable_list: hm_variable.hm_set(value) hass.services.register(DOMAIN, SERVICE_SET_VALUE, _service_handle_value, descriptions[DOMAIN][SERVICE_SET_VALUE], schema=SCHEMA_SERVICE_SET_VALUE) return True
def setup(hass, config): """Setup the OpenAlpr component.""" engine = config[DOMAIN].get(CONF_ENGINE) region = config[DOMAIN].get(CONF_REGION) confidence = config[DOMAIN].get(CONF_CONFIDENCE) api_key = config[DOMAIN].get(CONF_API_KEY) binary = config[DOMAIN].get(CONF_ALPR_BINARY) use_render_fffmpeg = False component = EntityComponent(_LOGGER, DOMAIN, hass) openalpr_device = [] for device in config[DOMAIN].get(CONF_ENTITIES): input_source = device.get(CONF_INPUT) render = device.get(CONF_RENDER) ## # create api if engine == ENGINE_LOCAL: alpr_api = OpenalprApiLocal( confidence=confidence, region=region, binary=binary, ) else: alpr_api = OpenalprApiCloud( confidence=confidence, region=region, api_key=api_key, ) ## # Create Alpr device / render engine if render == RENDER_FFMPEG: use_render_fffmpeg = True if not run_test(input_source): _LOGGER.error("'%s' is not valid ffmpeg input", input_source) continue alpr_dev = OpenalprDeviceFFmpeg( name=device.get(CONF_NAME), interval=device.get(CONF_INTERVAL), api=alpr_api, input_source=input_source, extra_arguments=device.get(CONF_EXTRA_ARGUMENTS), ) else: alpr_dev = OpenalprDeviceImage( name=device.get(CONF_NAME), interval=device.get(CONF_INTERVAL), api=alpr_api, input_source=input_source, username=device.get(CONF_USERNAME), password=device.get(CONF_PASSWORD), ) # register shutdown event openalpr_device.append(alpr_dev) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, alpr_dev.shutdown) component.add_entities(openalpr_device) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def _handle_service_scan(service): """Handle service for immediately scan.""" device_list = component.extract_from_service(service) for device in device_list: device.scan() hass.services.register(DOMAIN, SERVICE_SCAN, _handle_service_scan, descriptions[DOMAIN][SERVICE_SCAN], schema=SERVICE_SCAN_SCHEMA) # Add restart service only if a device use ffmpeg as render if not use_render_fffmpeg: return True def _handle_service_restart(service): """Handle service for restart ffmpeg process.""" device_list = component.extract_from_service(service) for device in device_list: device.restart() hass.services.register(DOMAIN, SERVICE_RESTART, _handle_service_restart, descriptions[DOMAIN][SERVICE_RESTART], schema=SERVICE_RESTART_SCHEMA) return True
def setup(hass, config): """Set up the Wink component.""" import pywink from pubnubsubhandler import PubNubSubscriptionHandler descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) if hass.data.get(DOMAIN) is None: hass.data[DOMAIN] = { 'unique_ids': [], 'entities': {}, 'oauth': {}, 'configuring': {}, 'pubnub': None, 'configurator': False } if config.get(DOMAIN) is not None: client_id = config[DOMAIN].get(ATTR_CLIENT_ID) client_secret = config[DOMAIN].get(ATTR_CLIENT_SECRET) email = config[DOMAIN].get(CONF_EMAIL) password = config[DOMAIN].get(CONF_PASSWORD) local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL) else: client_id = None client_secret = None email = None password = None local_control = None hass.data[DOMAIN]['configurator'] = True if None not in [client_id, client_secret]: _LOGGER.info("Using legacy oauth authentication") if not local_control: pywink.disable_local_control() hass.data[DOMAIN]["oauth"]["client_id"] = client_id hass.data[DOMAIN]["oauth"]["client_secret"] = client_secret hass.data[DOMAIN]["oauth"]["email"] = email hass.data[DOMAIN]["oauth"]["password"] = password pywink.legacy_set_wink_credentials(email, password, client_id, client_secret) else: _LOGGER.info("Using oauth authentication") if not local_control: pywink.disable_local_control() config_path = hass.config.path(WINK_CONFIG_FILE) if os.path.isfile(config_path): config_file = load_json(config_path) if config_file == DEFAULT_CONFIG: _request_app_setup(hass, config) return True # else move on because the user modified the file else: save_json(config_path, DEFAULT_CONFIG) _request_app_setup(hass, config) return True if DOMAIN in hass.data[DOMAIN]['configuring']: _configurator = hass.data[DOMAIN]['configuring'] hass.components.configurator.request_done(_configurator.pop( DOMAIN)) # Using oauth access_token = config_file.get(ATTR_ACCESS_TOKEN) refresh_token = config_file.get(ATTR_REFRESH_TOKEN) # This will be called after authorizing Home-Assistant if None not in (access_token, refresh_token): pywink.set_wink_credentials(config_file.get(ATTR_CLIENT_ID), config_file.get(ATTR_CLIENT_SECRET), access_token=access_token, refresh_token=refresh_token) # This is called to create the redirect so the user can Authorize # Home-Assistant else: redirect_uri = '{}{}'.format(hass.config.api.base_url, WINK_AUTH_CALLBACK_PATH) wink_auth_start_url = pywink.get_authorization_url( config_file.get(ATTR_CLIENT_ID), redirect_uri) hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url) hass.http.register_view(WinkAuthCallbackView(config, config_file, pywink.request_token)) _request_oauth_completion(hass, config) return True pywink.set_user_agent(USER_AGENT) hass.data[DOMAIN]['pubnub'] = PubNubSubscriptionHandler( pywink.get_subscription_key()) def _subscribe(): hass.data[DOMAIN]['pubnub'].subscribe() # Call subscribe after the user sets up wink via the configurator # All other methods will complete setup before # EVENT_HOMEASSISTANT_START is called meaning they # will call subscribe via the method below. (start_subscription) if hass.data[DOMAIN]['configurator']: _subscribe() def keep_alive_call(event_time): """Call the Wink API endpoints to keep PubNub working.""" _LOGGER.info("Polling the Wink API to keep PubNub updates flowing.") pywink.set_user_agent(str(int(time.time()))) _temp_response = pywink.get_user() _LOGGER.debug(str(json.dumps(_temp_response))) time.sleep(1) pywink.set_user_agent(USER_AGENT) _temp_response = pywink.wink_api_fetch() _LOGGER.debug(str(json.dumps(_temp_response))) # Call the Wink API every hour to keep PubNub updates flowing track_time_interval(hass, keep_alive_call, timedelta(minutes=60)) def start_subscription(event): """Start the pubnub subscription.""" _subscribe() hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription) def stop_subscription(event): """Stop the pubnub subscription.""" hass.data[DOMAIN]['pubnub'].unsubscribe() hass.data[DOMAIN]['pubnub'] = None hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription) def save_credentials(event): """Save currently set oauth credentials.""" if hass.data[DOMAIN]["oauth"].get("email") is None: config_path = hass.config.path(WINK_CONFIG_FILE) _config = pywink.get_current_oauth_credentials() save_json(config_path, _config) hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials) def force_update(call): """Force all devices to poll the Wink API.""" _LOGGER.info("Refreshing Wink states from API") for entity_list in hass.data[DOMAIN]['entities'].values(): # Throttle the calls to Wink API for entity in entity_list: time.sleep(1) entity.schedule_update_ha_state(True) hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update, descriptions.get(SERVICE_REFRESH_STATES)) def pull_new_devices(call): """Pull new devices added to users Wink account since startup.""" _LOGGER.info("Getting new devices from Wink API") for _component in WINK_COMPONENTS: discovery.load_platform(hass, _component, DOMAIN, {}, config) hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices, descriptions.get(SERVICE_ADD_NEW_DEVICES)) def set_pairing_mode(call): """Put the hub in provided pairing mode.""" hub_name = call.data.get('hub_name') pairing_mode = call.data.get('pairing_mode') kidde_code = call.data.get('kidde_radio_code') for hub in WINK_HUBS: if hub.name() == hub_name: hub.pair_new_device(pairing_mode, kidde_radio_code=kidde_code) def rename_device(call): """Set specified device's name.""" # This should only be called on one device at a time. found_device = None entity_id = call.data.get('entity_id')[0] all_devices = [] for list_of_devices in hass.data[DOMAIN]['entities'].values(): all_devices += list_of_devices for device in all_devices: if device.entity_id == entity_id: found_device = device if found_device is not None: name = call.data.get('name') found_device.wink.set_name(name) hass.services.register(DOMAIN, SERVICE_RENAME_DEVICE, rename_device, descriptions.get(SERVICE_RENAME_DEVICE), schema=RENAME_DEVICE_SCHEMA) def delete_device(call): """Delete specified device.""" # This should only be called on one device at a time. found_device = None entity_id = call.data.get('entity_id')[0] all_devices = [] for list_of_devices in hass.data[DOMAIN]['entities'].values(): all_devices += list_of_devices for device in all_devices: if device.entity_id == entity_id: found_device = device if found_device is not None: found_device.wink.remove_device() hass.services.register(DOMAIN, SERVICE_DELETE_DEVICE, delete_device, descriptions.get(SERVICE_DELETE_DEVICE), schema=DELETE_DEVICE_SCHEMA) hubs = pywink.get_hubs() for hub in hubs: if hub.device_manufacturer() == 'wink': WINK_HUBS.append(hub) if WINK_HUBS: hass.services.register( DOMAIN, SERVICE_SET_PAIRING_MODE, set_pairing_mode, descriptions.get(SERVICE_SET_PAIRING_MODE), schema=SET_PAIRING_MODE_SCHEMA) def service_handle(service): """Handler for services.""" entity_ids = service.data.get('entity_id') all_sirens = [] for switch in hass.data[DOMAIN]['entities']['switch']: if isinstance(switch, WinkSirenDevice): all_sirens.append(switch) sirens_to_set = [] if entity_ids is None: sirens_to_set = all_sirens else: for siren in all_sirens: if siren.entity_id in entity_ids: sirens_to_set.append(siren) for siren in sirens_to_set: if (service.service != SERVICE_SET_AUTO_SHUTOFF and service.service != SERVICE_ENABLE_SIREN and siren.wink.device_manufacturer() != 'dome'): _LOGGER.error("Service only valid for Dome sirens.") return if service.service == SERVICE_ENABLE_SIREN: siren.wink.set_state(service.data.get(ATTR_ENABLED)) elif service.service == SERVICE_SET_AUTO_SHUTOFF: siren.wink.set_auto_shutoff( service.data.get(ATTR_AUTO_SHUTOFF)) elif service.service == SERVICE_SET_CHIME_VOLUME: siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME)) elif service.service == SERVICE_SET_SIREN_VOLUME: siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME)) elif service.service == SERVICE_SET_SIREN_TONE: siren.wink.set_siren_sound(service.data.get(ATTR_TONE)) elif service.service == SERVICE_ENABLE_CHIME: siren.wink.set_chime(service.data.get(ATTR_TONE)) elif service.service == SERVICE_SIREN_STROBE_ENABLED: siren.wink.set_siren_strobe_enabled( service.data.get(ATTR_ENABLED)) elif service.service == SERVICE_CHIME_STROBE_ENABLED: siren.wink.set_chime_strobe_enabled( service.data.get(ATTR_ENABLED)) # Load components for the devices in Wink that we support for wink_component in WINK_COMPONENTS: hass.data[DOMAIN]['entities'][wink_component] = [] discovery.load_platform(hass, wink_component, DOMAIN, {}, config) component = EntityComponent(_LOGGER, DOMAIN, hass) sirens = [] has_dome_siren = False for siren in pywink.get_sirens(): if siren.device_manufacturer() == "dome": has_dome_siren = True _id = siren.object_id() + siren.name() if _id not in hass.data[DOMAIN]['unique_ids']: sirens.append(WinkSirenDevice(siren, hass)) if sirens: hass.services.register(DOMAIN, SERVICE_SET_AUTO_SHUTOFF, service_handle, descriptions.get(SERVICE_SET_AUTO_SHUTOFF), schema=SET_AUTO_SHUTOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_ENABLE_SIREN, service_handle, descriptions.get(SERVICE_ENABLE_SIREN), schema=ENABLED_SIREN_SCHEMA) if has_dome_siren: hass.services.register(DOMAIN, SERVICE_SET_SIREN_TONE, service_handle, descriptions.get(SERVICE_SET_SIREN_TONE), schema=SET_SIREN_TONE_SCHEMA) hass.services.register(DOMAIN, SERVICE_ENABLE_CHIME, service_handle, descriptions.get(SERVICE_ENABLE_CHIME), schema=SET_CHIME_MODE_SCHEMA) hass.services.register(DOMAIN, SERVICE_SET_SIREN_VOLUME, service_handle, descriptions.get(SERVICE_SET_SIREN_VOLUME), schema=SET_VOLUME_SCHEMA) hass.services.register(DOMAIN, SERVICE_SET_CHIME_VOLUME, service_handle, descriptions.get(SERVICE_SET_CHIME_VOLUME), schema=SET_VOLUME_SCHEMA) hass.services.register(DOMAIN, SERVICE_SIREN_STROBE_ENABLED, service_handle, descriptions.get(SERVICE_SIREN_STROBE_ENABLED), schema=SET_STROBE_ENABLED_SCHEMA) hass.services.register(DOMAIN, SERVICE_CHIME_STROBE_ENABLED, service_handle, descriptions.get(SERVICE_CHIME_STROBE_ENABLED), schema=SET_STROBE_ENABLED_SCHEMA) component.add_entities(sirens) return True