async def test_parallel_updates_sync_platform_with_constant(hass): """Test sync platform can set parallel_updates limit.""" platform = MockPlatform() platform.PARALLEL_UPDATES = 2 loader.set_component(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} await component.async_setup({ DOMAIN: { 'platform': 'platform', } }) handle = list(component._platforms.values())[-1] assert handle.parallel_updates == 2 class SyncEntity(MockEntity): """Mock entity that has update.""" async def update(self): pass entity = SyncEntity() await handle.async_add_entities([entity]) assert entity.parallel_updates is not None assert entity.parallel_updates._value == 2
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
async def async_setup(hass, config): """Set up an input text box.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): name = cfg.get(CONF_NAME) minimum = cfg.get(CONF_MIN) maximum = cfg.get(CONF_MAX) initial = cfg.get(CONF_INITIAL) icon = cfg.get(CONF_ICON) unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT) pattern = cfg.get(ATTR_PATTERN) mode = cfg.get(CONF_MODE) entities.append(InputText( object_id, name, initial, minimum, maximum, icon, unit, pattern, mode)) if not entities: return False component.async_register_entity_service( SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA, 'async_set_value' ) await component.async_add_entities(entities) return True
def setup(hass, config): """ Track states and offer events for remote. """ 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 remote_service_handler(service): """ Maps services to methods on RemoteDevice. """ target_remotes = component.extract_from_service(service) method = SERVICE_TO_METHOD[service.service] for remote in target_remotes: getattr(remote, method)() if remote.should_poll: remote.update_ha_state(True) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, remote_service_handler, descriptions.get(service)) return True
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) if ATTR_CODE not in service.data: code = None else: code = service.data[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)) hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, descriptions.get(SERVICE_LOCK)) return True
def test_setup_dependencies_platform(hass): """Test we setup the dependencies of a platform. We're explictely testing that we process dependencies even if a component with the same name has already been loaded. """ loader.set_component(hass, 'test_component', MockModule('test_component')) loader.set_component(hass, 'test_component2', MockModule('test_component2')) loader.set_component( hass, 'test_domain.test_component', MockPlatform(dependencies=['test_component', 'test_component2'])) component = EntityComponent(_LOGGER, DOMAIN, hass) yield from async_setup_component(hass, 'test_component', {}) yield from component.async_setup({ DOMAIN: { 'platform': 'test_component', } }) assert 'test_component' in hass.config.components assert 'test_component2' in hass.config.components assert 'test_domain.test_component' in hass.config.components
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 async_setup(hass, config): """Track states and offer events for covers.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_COVERS) yield from component.async_setup(config) @asyncio.coroutine def async_handle_cover_service(service): """Handle calls to the cover services.""" covers = component.async_extract_from_service(service) method = SERVICE_TO_METHOD.get(service.service) params = service.data.copy() params.pop(ATTR_ENTITY_ID, None) # call method update_tasks = [] for cover in covers: yield from getattr(cover, method['method'])(**params) if not cover.should_poll: continue update_tasks.append(cover.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for service_name in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service_name].get( 'schema', COVER_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, service_name, async_handle_cover_service, schema=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([ MockEntity(name='beer'), MockEntity(name=None), ]) platform = MockPlatform(platform_setup) loader.set_component(self.hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) component.setup({ DOMAIN: { 'platform': 'platform', 'entity_namespace': 'yummy' } }) self.hass.block_till_done() assert sorted(self.hass.states.entity_ids()) == \ ['test_domain.yummy_beer', 'test_domain.yummy_unnamed_device']
def setup(hass, config): """Track states and offer events for covers.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_COVERS) component.setup(config) def handle_cover_service(service): """Handle calls to the cover services.""" method = SERVICE_TO_METHOD.get(service.service) params = service.data.copy() params.pop(ATTR_ENTITY_ID, None) if method: for cover in component.extract_from_service(service): getattr(cover, method['method'])(**params) if cover.should_poll: cover.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) for service_name in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service_name].get( 'schema', COVER_SERVICE_SCHEMA) hass.services.register(DOMAIN, service_name, handle_cover_service, descriptions.get(service_name), schema=schema) return True
def setup(hass, config): """Track states and offer events for switches.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, 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 async_setup(hass, config): """Track states and offer events for calendars.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DOMAIN) yield from component.async_setup(config) 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): """ Handles 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)) hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, descriptions.get(SERVICE_CLOSE)) 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): """Setup scenes.""" logger = logging.getLogger(__name__) # You are not allowed to mutate the original config so make a copy config = dict(config) for config_key in extract_domain_configs(config, DOMAIN): platform_config = config[config_key] if not isinstance(platform_config, list): platform_config = [platform_config] if not any(CONF_PLATFORM in entry for entry in platform_config): platform_config = [{'platform': 'homeassistant', 'states': entry} for entry in platform_config] config[config_key] = platform_config component = EntityComponent(logger, DOMAIN, hass) component.setup(config) def handle_scene_service(service): """Handle calls to the switch services.""" target_scenes = component.extract_from_service(service) for scene in target_scenes: scene.activate() hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_scene_service, schema=SCENE_SERVICE_SCHEMA) return True
def async_setup(hass, config): """Track states and offer events for binary sensors.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) yield from component.async_setup(config) return True
def async_setup(hass, config: dict): """Expose fan control via statemachine and services.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_FANS) yield from component.async_setup(config) @asyncio.coroutine def async_handle_fan_service(service): """Handle service call for fans.""" method = SERVICE_TO_METHOD.get(service.service) params = service.data.copy() # Convert the entity ids to valid fan ids target_fans = component.async_extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) update_tasks = [] for fan in target_fans: yield from getattr(fan, method['method'])(**params) if not fan.should_poll: continue update_tasks.append(fan.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for service_name in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service_name].get('schema') hass.services.async_register( DOMAIN, service_name, async_handle_fan_service, schema=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 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 async_setup(hass, config): """Track states and offer events for sensors.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) yield from component.async_setup(config) @asyncio.coroutine def async_alarm_service_handler(service): """Map services to methods on Alarm.""" target_alarms = component.async_extract_from_service(service) code = service.data.get(ATTR_CODE) method = "async_{}".format(SERVICE_TO_METHOD[service.service]) update_tasks = [] for alarm in target_alarms: yield from getattr(alarm, method)(code) if not alarm.should_poll: continue update_tasks.append(alarm.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for service in SERVICE_TO_METHOD: hass.services.async_register( DOMAIN, service, async_alarm_service_handler, schema=ALARM_SERVICE_SCHEMA) return True
def async_setup(hass, config): """Set up the vacuum component.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_VACUUMS) yield from component.async_setup(config) @asyncio.coroutine def async_handle_vacuum_service(service): """Map services to methods on VacuumDevice.""" method = SERVICE_TO_METHOD.get(service.service) target_vacuums = component.async_extract_from_service(service) params = service.data.copy() params.pop(ATTR_ENTITY_ID, None) update_tasks = [] for vacuum in target_vacuums: yield from getattr(vacuum, method['method'])(**params) if not vacuum.should_poll: continue update_tasks.append(vacuum.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service].get( 'schema', VACUUM_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, service, async_handle_vacuum_service, schema=schema) return True
def setup(hass, config): """Track states and offer events for sensors.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, 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) if ATTR_CODE not in service.data: code = None else: code = service.data[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: hass.services.register(DOMAIN, service, alarm_service_handler, descriptions.get(service)) return True
def async_setup(hass, config): """Setup input select.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): name = cfg.get(CONF_NAME) options = cfg.get(CONF_OPTIONS) state = cfg.get(CONF_INITIAL, options[0]) icon = cfg.get(CONF_ICON) entities.append(InputSelect(object_id, name, state, options, icon)) if not entities: return False @asyncio.coroutine def async_select_option_service(call): """Handle a calls to the input select option service.""" target_inputs = component.async_extract_from_service(call) tasks = [input_select.async_select_option(call.data[ATTR_OPTION]) for input_select in target_inputs] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_SELECT_OPTION, async_select_option_service, schema=SERVICE_SELECT_OPTION_SCHEMA) @asyncio.coroutine def async_select_next_service(call): """Handle a calls to the input select next service.""" target_inputs = component.async_extract_from_service(call) tasks = [input_select.async_offset_index(1) for input_select in target_inputs] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_SELECT_NEXT, async_select_next_service, schema=SERVICE_SELECT_NEXT_SCHEMA) @asyncio.coroutine def async_select_previous_service(call): """Handle a calls to the input select previous service.""" target_inputs = component.async_extract_from_service(call) tasks = [input_select.async_offset_index(-1) for input_select in target_inputs] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_SELECT_PREVIOUS, async_select_previous_service, schema=SERVICE_SELECT_PREVIOUS_SCHEMA) yield from component.async_add_entities(entities) return True
def test_pararell_updates_async_platform_with_constant(hass): """Warn we log when platform setup takes a long time.""" platform = MockPlatform() @asyncio.coroutine def mock_update(*args, **kwargs): pass platform.async_setup_platform = mock_update platform.PARALLEL_UPDATES = 1 loader.set_component('test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} yield from component.async_setup({ DOMAIN: { 'platform': 'platform', } }) handle = list(component._platforms.values())[-1] assert handle.parallel_updates is not None
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 async_setup(hass, config): """Track states and offer events for remotes.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_REMOTES) yield from component.async_setup(config) component.async_register_entity_service( SERVICE_TURN_OFF, REMOTE_SERVICE_ACTIVITY_SCHEMA, 'async_turn_off' ) component.async_register_entity_service( SERVICE_TURN_ON, REMOTE_SERVICE_ACTIVITY_SCHEMA, 'async_turn_on' ) component.async_register_entity_service( SERVICE_TOGGLE, REMOTE_SERVICE_ACTIVITY_SCHEMA, 'async_toggle' ) component.async_register_entity_service( SERVICE_SEND_COMMAND, REMOTE_SERVICE_SEND_COMMAND_SCHEMA, 'async_send_command' ) return True
def test_entity_with_name_and_entity_id_getting_registered(hass): """Ensure that entity ID is used for registration.""" component = EntityComponent(_LOGGER, DOMAIN, hass) yield from component.async_add_entities([ MockEntity(unique_id='1234', name='bla', entity_id='test_domain.world')]) assert 'test_domain.world' in hass.states.async_entity_ids()
def 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 setup(hass, config): """ Track states and offer events for sensors. """ component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) def alarm_service_handler(service): """ Maps services to methods on Alarm. """ target_alarms = component.extract_from_service(service) if ATTR_CODE not in service.data: return code = service.data[ATTR_CODE] method = SERVICE_TO_METHOD[service.service] for alarm in target_alarms: getattr(alarm, method)(code) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, alarm_service_handler) return True
def test_not_fails_with_adding_empty_entities_(hass): """Test for not fails on empty entities list.""" component = EntityComponent(_LOGGER, DOMAIN, hass) yield from component.async_add_entities([]) assert len(hass.states.async_entity_ids()) == 0
def async_setup(hass, config): """Set up image processing.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) yield from component.async_setup(config) descriptions = yield from hass.async_add_job( load_yaml_config_file, os.path.join(os.path.dirname(__file__), 'services.yaml')) @asyncio.coroutine def async_scan_service(service): """Service handler for scan.""" image_entities = component.async_extract_from_service(service) update_task = [entity.async_update_ha_state(True) for entity in image_entities] if update_task: yield from asyncio.wait(update_task, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_SCAN, async_scan_service, descriptions.get(SERVICE_SCAN), schema=SERVICE_SCAN_SCHEMA) return True
def async_setup(hass, config): """Track states and offer events for calendars.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DOMAIN) yield from component.async_setup(config) return True
async def async_setup(hass, config): """Expose light control via state machine and services.""" component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) await component.async_setup(config) profiles = hass.data[DATA_PROFILES] = Profiles(hass) await profiles.async_initialize() def preprocess_data(data): """Preprocess the service data.""" base = { entity_field: data.pop(entity_field) for entity_field in cv.ENTITY_SERVICE_FIELDS if entity_field in data } preprocess_turn_on_alternatives(hass, data) base["params"] = data return base async def async_handle_light_on_service(light, call): """Handle turning a light on. If brightness is set to 0, this service will turn the light off. """ params = dict(call.data["params"]) # Only process params once we processed brightness step if params and (ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params): brightness = light.brightness if light.is_on else 0 if ATTR_BRIGHTNESS_STEP in params: brightness += params.pop(ATTR_BRIGHTNESS_STEP) else: brightness += round( params.pop(ATTR_BRIGHTNESS_STEP_PCT) / 100 * 255) params[ATTR_BRIGHTNESS] = max(0, min(255, brightness)) preprocess_turn_on_alternatives(hass, params) if ATTR_PROFILE not in params: profiles.apply_default(light.entity_id, params) supported_color_modes = light.supported_color_modes # Backwards compatibility: if an RGBWW color is specified, convert to RGB + W # for legacy lights if ATTR_RGBW_COLOR in params: legacy_supported_color_modes = ( light._light_internal_supported_color_modes # pylint: disable=protected-access ) if (COLOR_MODE_RGBW in legacy_supported_color_modes and not supported_color_modes): rgbw_color = params.pop(ATTR_RGBW_COLOR) params[ATTR_RGB_COLOR] = rgbw_color[0:3] params[ATTR_WHITE_VALUE] = rgbw_color[3] # If a color is specified, convert to the color space supported by the light # Backwards compatibility: Fall back to hs color if light.supported_color_modes # is not implemented if not supported_color_modes: if (rgb_color := params.pop(ATTR_RGB_COLOR, None)) is not None: params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color) elif (xy_color := params.pop(ATTR_XY_COLOR, None)) is not None: params[ATTR_HS_COLOR] = color_util.color_xy_to_hs(*xy_color)
def test_using_prescribed_entity_id(hass): """Test for using predefined entity ID.""" component = EntityComponent(_LOGGER, DOMAIN, hass) yield from component.async_add_entities([ MockEntity(name='bla', entity_id='hello.world')]) assert 'hello.world' in hass.states.async_entity_ids()
def setup(hass, config): """Setup zigate platform.""" import zigate port = config[DOMAIN].get(CONF_PORT) host = config[DOMAIN].get(CONF_HOST) persistent_file = os.path.join(hass.config.config_dir, '.zigate.json') myzigate = zigate.connect(port=port, host=host, path=persistent_file, auto_start=False) # if host: # host = host.split(':', 1) # port = None # if len(host) == 2: # port = int(host[1]) # myzigate = zigate.ZiGateWiFi(host[0], # port, # path=persistent_file, # auto_start=False) # else: # myzigate = zigate.ZiGate(port, # path=persistent_file, # auto_start=False) hass.data[DOMAIN] = myzigate hass.data[DATA_ZIGATE_DEVICES] = {} hass.data[DATA_ZIGATE_ATTRS] = {} component = EntityComponent(_LOGGER, DOMAIN, hass) def device_added(**kwargs): device = kwargs['device'] _LOGGER.debug('Add device {}'.format(device)) if device.addr not in hass.data[DATA_ZIGATE_DEVICES]: entity = ZiGateDeviceEntity(device) hass.data[DATA_ZIGATE_DEVICES][device.addr] = 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 addr = kwargs['addr'] hass.components.persistent_notification.create( 'The ZiGate device {} has leaved.'.format(addr), title='ZiGate') def device_need_refresh(**kwargs): device = kwargs['device'] hass.components.persistent_notification.create( ('The ZiGate device {} needs some' ' refresh (missing important' ' information)').format(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_refresh, zigate.ZIGATE_DEVICE_NEED_REFRESH, weak=False) def attribute_updated(**kwargs): device = kwargs['device'] attribute = kwargs['attribute'] _LOGGER.debug('Update attribute for device {} {}'.format( device, attribute)) key = '{}-{}-{}-{}'.format( device.addr, attribute['endpoint'], attribute['cluster'], attribute['attribute'], ) entity = hass.data[DATA_ZIGATE_ATTRS].get(key) if entity: if entity.hass: entity.schedule_update_ha_state() key = '{}-{}-{}'.format( device.addr, 'switch', attribute['endpoint'], ) entity = hass.data[DATA_ZIGATE_ATTRS].get(key) if entity: if entity.hass: entity.schedule_update_ha_state() key = '{}-{}-{}'.format( device.addr, 'light', attribute['endpoint'], ) entity = hass.data[DATA_ZIGATE_ATTRS].get(key) if entity: if entity.hass: entity.schedule_update_ha_state() entity = hass.data[DATA_ZIGATE_DEVICES].get(device.addr) if entity: if entity.hass: entity.schedule_update_ha_state() zigate.dispatcher.connect(attribute_updated, zigate.ZIGATE_ATTRIBUTE_UPDATED, weak=False) def device_updated(**kwargs): device = kwargs['device'] _LOGGER.debug('Update device {}'.format(device)) entity = hass.data[DATA_ZIGATE_DEVICES].get(device.addr) if entity: if entity.hass: entity.schedule_update_ha_state() else: _LOGGER.debug('Device not found {}, adding it'.format(device)) device_added(device=device) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_DEVICE_UPDATED, weak=False) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_ATTRIBUTE_ADDED, 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() myzigate.start_auto_save() version = myzigate.get_version_text() if version < '3.0d': hass.components.persistent_notification.create( ('Your zigate firmware is outdated, ' 'Please upgrade to 3.0d 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) def stop_zigate(service_event): myzigate.save_state() myzigate.close() def refresh_devices_list(service): myzigate.get_devices_list() def refresh_device(service): addr = service.data.get(ADDR) entity_id = service.data.get(ATTR_ENTITY_ID) if entity_id: entity = component.get_entity(entity_id) if entity: addr = entity._device.addr if addr: myzigate.refresh_device(addr) else: for device in myzigate.devices: device.refresh_device() def network_scan(service): myzigate.start_network_scan() def raw_command(service): cmd = int(service.data.get('cmd'), 16) data = service.data.get('data', '') myzigate.send_data(cmd, data) def identify_device(service): addr = service.data.get('addr') myzigate.identify_device(addr) def initiate_touchlink(service): myzigate.initiate_touchlink() def touchlink_factory_reset(service): myzigate.touchlink_factory_reset() 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, '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, '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, 'initiate_touchlink', initiate_touchlink) hass.services.register(DOMAIN, 'touchlink_factory_reset', touchlink_factory_reset) track_time_change(hass, refresh_devices_list, hour=0, minute=0, second=0) return True
def async_setup(hass, config): """Track states and offer events for remotes.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_REMOTES) yield from component.async_setup(config) component.async_register_entity_service(SERVICE_TURN_OFF, REMOTE_SERVICE_ACTIVITY_SCHEMA, 'async_turn_off') component.async_register_entity_service(SERVICE_TURN_ON, REMOTE_SERVICE_ACTIVITY_SCHEMA, 'async_turn_on') component.async_register_entity_service(SERVICE_TOGGLE, REMOTE_SERVICE_ACTIVITY_SCHEMA, 'async_toggle') component.async_register_entity_service( SERVICE_SEND_COMMAND, REMOTE_SERVICE_SEND_COMMAND_SCHEMA, 'async_send_command') return True
async def async_setup(hass, config): """Set up the Geolocation component.""" component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) await component.async_setup(config) return True
async def async_setup(hass, config): """Set up the camera component.""" component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) prefs = CameraPreferences(hass) await prefs.async_initialize() hass.data[DATA_CAMERA_PREFS] = prefs hass.http.register_view(CameraImageView(component)) hass.http.register_view(CameraMjpegStream(component)) hass.components.websocket_api.async_register_command( WS_TYPE_CAMERA_THUMBNAIL, websocket_camera_thumbnail, SCHEMA_WS_CAMERA_THUMBNAIL) hass.components.websocket_api.async_register_command(ws_camera_stream) hass.components.websocket_api.async_register_command(websocket_get_prefs) hass.components.websocket_api.async_register_command( websocket_update_prefs) await component.async_setup(config) async def preload_stream(_): for camera in component.entities: camera_prefs = prefs.get(camera.entity_id) if not camera_prefs.preload_stream: continue async with async_timeout.timeout(10): source = await camera.stream_source() if not source: continue request_stream(hass, source, keepalive=True, options=camera.stream_options) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, preload_stream) @callback def update_tokens(time): """Update tokens of the entities.""" for entity in component.entities: entity.async_update_token() entity.async_write_ha_state() hass.helpers.event.async_track_time_interval(update_tokens, TOKEN_CHANGE_INTERVAL) component.async_register_entity_service(SERVICE_ENABLE_MOTION, CAMERA_SERVICE_SCHEMA, "async_enable_motion_detection") component.async_register_entity_service(SERVICE_DISABLE_MOTION, CAMERA_SERVICE_SCHEMA, "async_disable_motion_detection") component.async_register_entity_service(SERVICE_TURN_OFF, CAMERA_SERVICE_SCHEMA, "async_turn_off") component.async_register_entity_service(SERVICE_TURN_ON, CAMERA_SERVICE_SCHEMA, "async_turn_on") component.async_register_entity_service(SERVICE_SNAPSHOT, CAMERA_SERVICE_SNAPSHOT, async_handle_snapshot_service) component.async_register_entity_service( SERVICE_PLAY_STREAM, CAMERA_SERVICE_PLAY_STREAM, async_handle_play_stream_service, ) component.async_register_entity_service(SERVICE_RECORD, CAMERA_SERVICE_RECORD, async_handle_record_service) return True
async def async_setup(hass, config): """Set up the automation.""" component = EntityComponent( _LOGGER, DOMAIN, hass, group_name=GROUP_NAME_ALL_AUTOMATIONS ) await _async_process_config(hass, config, component) async def trigger_service_handler(service_call): """Handle automation triggers.""" tasks = [] for entity in await component.async_extract_from_service(service_call): tasks.append( entity.async_trigger( service_call.data.get(ATTR_VARIABLES), skip_condition=True, context=service_call.context, ) ) if tasks: await asyncio.wait(tasks) async def turn_onoff_service_handler(service_call): """Handle automation turn on/off service calls.""" tasks = [] method = "async_{}".format(service_call.service) for entity in await component.async_extract_from_service(service_call): tasks.append(getattr(entity, method)()) if tasks: await asyncio.wait(tasks) async def toggle_service_handler(service_call): """Handle automation toggle service calls.""" tasks = [] for entity in await component.async_extract_from_service(service_call): if entity.is_on: tasks.append(entity.async_turn_off()) else: tasks.append(entity.async_turn_on()) if tasks: await asyncio.wait(tasks) async def reload_service_handler(service_call): """Remove all automations and load new ones from config.""" conf = await component.async_prepare_reload() if conf is None: return await _async_process_config(hass, conf, component) hass.services.async_register( DOMAIN, SERVICE_TRIGGER, trigger_service_handler, schema=TRIGGER_SERVICE_SCHEMA ) hass.services.async_register( DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA ) hass.services.async_register( DOMAIN, SERVICE_TOGGLE, toggle_service_handler, schema=ENTITY_SERVICE_SCHEMA ) for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF): hass.services.async_register( DOMAIN, service, turn_onoff_service_handler, schema=ENTITY_SERVICE_SCHEMA ) return True
def async_setup(hass, config): """Set up the camera component.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) hass.http.register_view(CameraImageView(component.entities)) hass.http.register_view(CameraMjpegStream(component.entities)) yield from component.async_setup(config) @callback def update_tokens(time): """Update tokens of the entities.""" for entity in component.entities.values(): entity.async_update_token() hass.async_add_job(entity.async_update_ha_state()) hass.helpers.event.async_track_time_interval( update_tokens, TOKEN_CHANGE_INTERVAL) @asyncio.coroutine def async_handle_camera_service(service): """Handle calls to the camera services.""" target_cameras = component.async_extract_from_service(service) update_tasks = [] for camera in target_cameras: if service.service == SERVICE_ENABLE_MOTION: yield from camera.async_enable_motion_detection() elif service.service == SERVICE_DISABLE_MOTION: yield from camera.async_disable_motion_detection() if not camera.should_poll: continue update_tasks.append(camera.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) @asyncio.coroutine def async_handle_snapshot_service(service): """Handle snapshot services calls.""" target_cameras = component.async_extract_from_service(service) filename = service.data[ATTR_FILENAME] filename.hass = hass for camera in target_cameras: snapshot_file = filename.async_render( variables={ATTR_ENTITY_ID: camera}) # check if we allow to access to that file if not hass.config.is_allowed_path(snapshot_file): _LOGGER.error( "Can't write %s, no access to path!", snapshot_file) continue image = yield from camera.async_camera_image() def _write_image(to_file, image_data): """Executor helper to write image.""" with open(to_file, 'wb') as img_file: img_file.write(image_data) try: yield from hass.async_add_job( _write_image, snapshot_file, image) except OSError as err: _LOGGER.error("Can't write image to file: %s", err) descriptions = yield from hass.async_add_job( load_yaml_config_file, os.path.join( os.path.dirname(__file__), 'services.yaml')) hass.services.async_register( DOMAIN, SERVICE_ENABLE_MOTION, async_handle_camera_service, descriptions.get(SERVICE_ENABLE_MOTION), schema=CAMERA_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, SERVICE_DISABLE_MOTION, async_handle_camera_service, descriptions.get(SERVICE_DISABLE_MOTION), schema=CAMERA_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, SERVICE_SNAPSHOT, async_handle_snapshot_service, descriptions.get(SERVICE_SNAPSHOT), schema=CAMERA_SERVICE_SNAPSHOT) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Expose fan control via statemachine and services.""" component = hass.data[DOMAIN] = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL ) await component.async_setup(config) # After the transition to percentage and preset_modes concludes, # switch this back to async_turn_on and remove async_turn_on_compat component.async_register_entity_service( SERVICE_TURN_ON, { vol.Optional(ATTR_PERCENTAGE): vol.All( vol.Coerce(int), vol.Range(min=0, max=100) ), vol.Optional(ATTR_PRESET_MODE): cv.string, }, "async_turn_on", ) component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") component.async_register_entity_service( SERVICE_INCREASE_SPEED, { vol.Optional(ATTR_PERCENTAGE_STEP): vol.All( vol.Coerce(int), vol.Range(min=0, max=100) ) }, "async_increase_speed", [FanEntityFeature.SET_SPEED], ) component.async_register_entity_service( SERVICE_DECREASE_SPEED, { vol.Optional(ATTR_PERCENTAGE_STEP): vol.All( vol.Coerce(int), vol.Range(min=0, max=100) ) }, "async_decrease_speed", [FanEntityFeature.SET_SPEED], ) component.async_register_entity_service( SERVICE_OSCILLATE, {vol.Required(ATTR_OSCILLATING): cv.boolean}, "async_oscillate", [FanEntityFeature.OSCILLATE], ) component.async_register_entity_service( SERVICE_SET_DIRECTION, {vol.Optional(ATTR_DIRECTION): cv.string}, "async_set_direction", [FanEntityFeature.DIRECTION], ) component.async_register_entity_service( SERVICE_SET_PERCENTAGE, { vol.Required(ATTR_PERCENTAGE): vol.All( vol.Coerce(int), vol.Range(min=0, max=100) ) }, "async_set_percentage", [FanEntityFeature.SET_SPEED], ) component.async_register_entity_service( SERVICE_SET_PRESET_MODE, {vol.Required(ATTR_PRESET_MODE): cv.string}, "async_set_preset_mode", [FanEntityFeature.SET_SPEED, FanEntityFeature.PRESET_MODE], ) return True
async def async_setup(hass, config): """Track states and offer events for media_players.""" component = hass.data[DOMAIN] = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) hass.components.websocket_api.async_register_command( WS_TYPE_MEDIA_PLAYER_THUMBNAIL, websocket_handle_thumbnail, SCHEMA_WEBSOCKET_GET_THUMBNAIL) hass.http.register_view(MediaPlayerImageView(component)) await component.async_setup(config) component.async_register_entity_service(SERVICE_TURN_ON, MEDIA_PLAYER_SCHEMA, 'async_turn_on') component.async_register_entity_service(SERVICE_TURN_OFF, MEDIA_PLAYER_SCHEMA, 'async_turn_off') component.async_register_entity_service(SERVICE_TOGGLE, MEDIA_PLAYER_SCHEMA, 'async_toggle') component.async_register_entity_service(SERVICE_VOLUME_UP, MEDIA_PLAYER_SCHEMA, 'async_volume_up') component.async_register_entity_service(SERVICE_VOLUME_DOWN, MEDIA_PLAYER_SCHEMA, 'async_volume_down') component.async_register_entity_service(SERVICE_MEDIA_PLAY_PAUSE, MEDIA_PLAYER_SCHEMA, 'async_media_play_pause') component.async_register_entity_service(SERVICE_MEDIA_PLAY, MEDIA_PLAYER_SCHEMA, 'async_media_play') component.async_register_entity_service(SERVICE_MEDIA_PAUSE, MEDIA_PLAYER_SCHEMA, 'async_media_pause') component.async_register_entity_service(SERVICE_MEDIA_STOP, MEDIA_PLAYER_SCHEMA, 'async_media_stop') component.async_register_entity_service(SERVICE_MEDIA_NEXT_TRACK, MEDIA_PLAYER_SCHEMA, 'async_media_next_track') component.async_register_entity_service(SERVICE_MEDIA_PREVIOUS_TRACK, MEDIA_PLAYER_SCHEMA, 'async_media_previous_track') component.async_register_entity_service(SERVICE_CLEAR_PLAYLIST, MEDIA_PLAYER_SCHEMA, 'async_clear_playlist') component.async_register_entity_service( SERVICE_VOLUME_SET, MEDIA_PLAYER_SET_VOLUME_SCHEMA, lambda entity, call: entity.async_set_volume_level(volume=call.data[ ATTR_MEDIA_VOLUME_LEVEL])) component.async_register_entity_service( SERVICE_VOLUME_MUTE, MEDIA_PLAYER_MUTE_VOLUME_SCHEMA, lambda entity, call: entity.async_mute_volume(mute=call.data[ ATTR_MEDIA_VOLUME_MUTED])) component.async_register_entity_service( SERVICE_MEDIA_SEEK, MEDIA_PLAYER_MEDIA_SEEK_SCHEMA, lambda entity, call: entity.async_media_seek(position=call.data[ ATTR_MEDIA_SEEK_POSITION])) component.async_register_entity_service(SERVICE_SELECT_SOURCE, MEDIA_PLAYER_SELECT_SOURCE_SCHEMA, 'async_select_source') component.async_register_entity_service( SERVICE_SELECT_SOUND_MODE, MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA, 'async_select_sound_mode') component.async_register_entity_service( SERVICE_PLAY_MEDIA, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA, lambda entity, call: entity.async_play_media( media_type=call.data[ATTR_MEDIA_CONTENT_TYPE], media_id=call.data[ATTR_MEDIA_CONTENT_ID], enqueue=call.data.get(ATTR_MEDIA_ENQUEUE))) component.async_register_entity_service(SERVICE_SHUFFLE_SET, MEDIA_PLAYER_SET_SHUFFLE_SCHEMA, 'async_set_shuffle') return True
async def async_setup(hass, config): """Load the scripts from the configuration.""" hass.data[DOMAIN] = component = EntityComponent(_LOGGER, DOMAIN, hass) await _async_process_config(hass, config, component) async def reload_service(service): """Call a service to reload scripts.""" conf = await component.async_prepare_reload() if conf is None: return await _async_process_config(hass, conf, component) async def turn_on_service(service): """Call a service to turn script on.""" variables = service.data.get(ATTR_VARIABLES) for script_entity in await component.async_extract_from_service(service ): if script_entity.script.is_legacy: await hass.services.async_call(DOMAIN, script_entity.object_id, variables, context=service.context) else: await script_entity.async_turn_on(variables=variables, context=service.context, wait=False) async def turn_off_service(service): """Cancel a script.""" # Stopping a script is ok to be done in parallel scripts = await component.async_extract_from_service(service) if not scripts: return await asyncio.wait([script.async_turn_off() for script in scripts]) async def toggle_service(service): """Toggle a script.""" for script_entity in await component.async_extract_from_service(service ): await script_entity.async_toggle(context=service.context) hass.services.async_register(DOMAIN, SERVICE_RELOAD, reload_service, schema=RELOAD_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TURN_ON, turn_on_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TURN_OFF, turn_off_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TOGGLE, toggle_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) return True
async def async_setup(hass, config): """Set up variables from config.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if not cfg: cfg = {} initial_value = cfg.get(CONF_INITIAL_VALUE) unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT) restore = cfg.get(CONF_RESTORE, True) force_update = cfg.get(CONF_FORCE_UPDATE, False) friendly_name = cfg.get(ATTR_FRIENDLY_NAME, object_id) icon = cfg.get(CONF_ICON) entity_picture = cfg.get(ATTR_ENTITY_PICTURE) value_template = cfg.get(CONF_VALUE_TEMPLATE) friendly_name_template = cfg.get(CONF_FRIENDLY_NAME_TEMPLATE) icon_template = cfg.get(CONF_ICON_TEMPLATE) entity_picture_template = cfg.get(CONF_ENTITY_PICTURE_TEMPLATE) for template in ( value_template, icon_template, entity_picture_template, friendly_name_template, ): if template is not None: template.hass = hass manual_entity_ids = cfg.get(CONF_TRACKED_ENTITY_ID) tracked_entity_ids = list() if manual_entity_ids is not None: tracked_entity_ids = list(set(manual_entity_ids)) tracked_event_types = cfg.get(CONF_TRACKED_EVENT_TYPE) if tracked_event_types is not None: tracked_event_types = list(set(tracked_event_types)) query = cfg.get(CONF_QUERY) column = cfg.get(CONF_COLUMN) session = hass.data[recorder.DATA_INSTANCE].get_session() entities.append( Variable(hass, object_id, initial_value, value_template, session, query, column, unit, restore, force_update, friendly_name, friendly_name_template, icon, icon_template, entity_picture, entity_picture_template, tracked_entity_ids, tracked_event_types)) if not entities: return False component.async_register_entity_service(SERVICE_SET, SERVICE_SET_SCHEMA, 'async_set') component.async_register_entity_service(SERVICE_UPDATE, SERVICE_UPDATE_SCHEMA, 'async_force_update') await component.async_add_entities(entities) return True
def setup(hass, config): """Set up the Wink component.""" import pywink from pubnubsubhandler import PubNubSubscriptionHandler 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 . 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) # 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 service_handle(service): """Handle 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 != 'dome' and _man != '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 == "dome" or _man == "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, service_handle, schema=SET_AUTO_SHUTOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_ENABLE_SIREN, service_handle, schema=ENABLED_SIREN_SCHEMA) if has_dome_or_wink_siren: hass.services.register(DOMAIN, SERVICE_SET_SIREN_TONE, service_handle, schema=SET_SIREN_TONE_SCHEMA) hass.services.register(DOMAIN, SERVICE_ENABLE_CHIME, service_handle, schema=SET_CHIME_MODE_SCHEMA) hass.services.register(DOMAIN, SERVICE_SET_SIREN_VOLUME, service_handle, schema=SET_VOLUME_SCHEMA) hass.services.register(DOMAIN, SERVICE_SET_CHIME_VOLUME, service_handle, schema=SET_VOLUME_SCHEMA) hass.services.register(DOMAIN, SERVICE_SIREN_STROBE_ENABLED, service_handle, schema=SET_STROBE_ENABLED_SCHEMA) hass.services.register(DOMAIN, SERVICE_CHIME_STROBE_ENABLED, service_handle, schema=SET_STROBE_ENABLED_SCHEMA) component.add_entities(sirens) return True
async def async_setup(hass, config): """Set up all groups found defined in the configuration.""" component = hass.data.get(DOMAIN) if component is None: component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass) await _async_process_config(hass, config, component) async def reload_service_handler(service): """Remove all user-defined groups and load new ones from config.""" auto = list(filter(lambda e: not e.user_defined, component.entities)) conf = await component.async_prepare_reload() if conf is None: return await _async_process_config(hass, conf, component) await component.async_add_entities(auto) hass.services.async_register(DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA) async def groups_service_handler(service): """Handle dynamic group service functions.""" object_id = service.data[ATTR_OBJECT_ID] entity_id = ENTITY_ID_FORMAT.format(object_id) group = component.get_entity(entity_id) # new group if service.service == SERVICE_SET and group is None: entity_ids = service.data.get(ATTR_ENTITIES) or \ service.data.get(ATTR_ADD_ENTITIES) or None extra_arg = { attr: service.data[attr] for attr in (ATTR_VISIBLE, ATTR_ICON, ATTR_VIEW, ATTR_CONTROL) if service.data.get(attr) is not None } await Group.async_create_group(hass, service.data.get( ATTR_NAME, object_id), object_id=object_id, entity_ids=entity_ids, user_defined=False, **extra_arg) return if group is None: _LOGGER.warning("%s:Group '%s' doesn't exist!", service.service, object_id) return # update group if service.service == SERVICE_SET: need_update = False if ATTR_ADD_ENTITIES in service.data: delta = service.data[ATTR_ADD_ENTITIES] entity_ids = set(group.tracking) | set(delta) await group.async_update_tracked_entity_ids(entity_ids) if ATTR_ENTITIES in service.data: entity_ids = service.data[ATTR_ENTITIES] await group.async_update_tracked_entity_ids(entity_ids) if ATTR_NAME in service.data: group.name = service.data[ATTR_NAME] need_update = True if ATTR_VISIBLE in service.data: group.visible = service.data[ATTR_VISIBLE] need_update = True if ATTR_ICON in service.data: group.icon = service.data[ATTR_ICON] need_update = True if ATTR_CONTROL in service.data: group.control = service.data[ATTR_CONTROL] need_update = True if ATTR_VIEW in service.data: group.view = service.data[ATTR_VIEW] need_update = True if need_update: await group.async_update_ha_state() return # remove group if service.service == SERVICE_REMOVE: await component.async_remove_entity(entity_id) hass.services.async_register(DOMAIN, SERVICE_SET, groups_service_handler, schema=SET_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_REMOVE, groups_service_handler, schema=REMOVE_SERVICE_SCHEMA) async def visibility_service_handler(service): """Change visibility of a group.""" visible = service.data.get(ATTR_VISIBLE) tasks = [] for group in component.async_extract_from_service(service, expand_group=False): group.visible = visible tasks.append(group.async_update_ha_state()) if tasks: await asyncio.wait(tasks, loop=hass.loop) hass.services.async_register(DOMAIN, SERVICE_SET_VISIBILITY, visibility_service_handler, schema=SET_VISIBILITY_SERVICE_SCHEMA) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up an Utility Meter.""" hass.data[DATA_LEGACY_COMPONENT] = EntityComponent(_LOGGER, DOMAIN, hass) hass.data[DATA_UTILITY] = {} async def async_reset_meters(service_call): """Reset all sensors of a meter.""" meters = service_call.data["entity_id"] for meter in meters: _LOGGER.debug("resetting meter %s", meter) domain, entity = split_entity_id(meter) # backward compatibility up to 2022.07: if domain == DOMAIN: async_dispatcher_send(hass, SIGNAL_RESET_METER, f"{SELECT_DOMAIN}.{entity}") else: async_dispatcher_send(hass, SIGNAL_RESET_METER, meter) hass.services.async_register( DOMAIN, SERVICE_RESET, async_reset_meters, vol.Schema({ATTR_ENTITY_ID: vol.All(cv.ensure_list, [cv.entity_id])}), ) if DOMAIN not in config: return True for meter, conf in config[DOMAIN].items(): _LOGGER.debug("Setup %s.%s", DOMAIN, meter) hass.data[DATA_UTILITY][meter] = conf hass.data[DATA_UTILITY][meter][DATA_TARIFF_SENSORS] = [] if not conf[CONF_TARIFFS]: # only one entity is required name = conf.get(CONF_NAME, meter) hass.async_create_task( discovery.async_load_platform( hass, SENSOR_DOMAIN, DOMAIN, {name: { CONF_METER: meter, CONF_NAME: name }}, config, )) else: # create tariff selection hass.async_create_task( discovery.async_load_platform( hass, SELECT_DOMAIN, DOMAIN, { CONF_METER: meter, CONF_TARIFFS: conf[CONF_TARIFFS] }, config, )) hass.data[DATA_UTILITY][meter][ CONF_TARIFF_ENTITY] = "{}.{}".format(SELECT_DOMAIN, meter) # add one meter for each tariff tariff_confs = {} for tariff in conf[CONF_TARIFFS]: name = f"{meter} {tariff}" tariff_confs[name] = { CONF_METER: meter, CONF_NAME: name, CONF_TARIFF: tariff, } hass.async_create_task( discovery.async_load_platform(hass, SENSOR_DOMAIN, DOMAIN, tariff_confs, config)) 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() # myzigate.start_adminpanel(mount='/zigateproxy') # adminpanel_setup(hass, 'zigateproxy') # hass.async_create_task( # hass.config_entries.flow.async_init( # DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={} # ) # ) return True
def async_setup(hass, config): """Track states and offer events for remotes.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_REMOTES) yield from component.async_setup(config) @asyncio.coroutine def async_handle_remote_service(service): """Handle calls to the remote services.""" target_remotes = component.async_extract_from_service(service) activity_id = service.data.get(ATTR_ACTIVITY) device = service.data.get(ATTR_DEVICE) command = service.data.get(ATTR_COMMAND) num_repeats = service.data.get(ATTR_NUM_REPEATS) delay_secs = service.data.get(ATTR_DELAY_SECS) update_tasks = [] for remote in target_remotes: if service.service == SERVICE_TURN_ON: yield from remote.async_turn_on(activity=activity_id) elif service.service == SERVICE_TOGGLE: yield from remote.async_toggle(activity=activity_id) elif service.service == SERVICE_SEND_COMMAND: yield from remote.async_send_command(device=device, command=command, num_repeats=num_repeats, delay_secs=delay_secs) else: yield from remote.async_turn_off(activity=activity_id) if not remote.should_poll: continue update_tasks.append(remote.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) descriptions = yield from hass.async_add_job( load_yaml_config_file, os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.async_register(DOMAIN, SERVICE_TURN_OFF, async_handle_remote_service, descriptions.get(SERVICE_TURN_OFF), schema=REMOTE_SERVICE_ACTIVITY_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TURN_ON, async_handle_remote_service, descriptions.get(SERVICE_TURN_ON), schema=REMOTE_SERVICE_ACTIVITY_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TOGGLE, async_handle_remote_service, descriptions.get(SERVICE_TOGGLE), schema=REMOTE_SERVICE_ACTIVITY_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_SEND_COMMAND, async_handle_remote_service, descriptions.get(SERVICE_SEND_COMMAND), schema=REMOTE_SERVICE_SEND_COMMAND_SCHEMA) return True
def setup(hass, config): """Setup zigate platform.""" from homeassistant.components import persistent_notification import zigate port = config.get(CONF_PORT) host = config.get(CONF_HOST) persistent_file = os.path.join(hass.config.config_dir, 'zigate.json') _LOGGER.debug('Persistent file {}'.format(persistent_file)) if host: if not port: port = 9999 z = zigate.ZiGateWiFi(host, port, path=persistent_file, auto_start=False) else: z = zigate.ZiGate(port, path=persistent_file, auto_start=False) hass.data[DOMAIN] = z hass.data[DATA_ZIGATE_DEVICES] = {} hass.data[DATA_ZIGATE_ATTRS] = {} component = EntityComponent(_LOGGER, DOMAIN, hass) def device_added(**kwargs): device = kwargs['device'] _LOGGER.debug('Add device {}'.format(device)) if device.addr not in hass.data[DATA_ZIGATE_DEVICES]: entity = ZiGateDeviceEntity(device) hass.data[DATA_ZIGATE_DEVICES][device.addr] = entity component.add_entities([entity]) if 'signal' in kwargs: persistent_notification.create( hass, ('A new ZiGate device "{}"' ' has been added !').format(device), title='ZiGate') def device_removed(**kwargs): # component.async_remove_entity pass def device_need_refresh(**kwargs): device = kwargs['device'] persistent_notification.create(hass, ('The ZiGate device {} needs some' ' refresh (missing important' ' information)').format(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_refresh, zigate.ZIGATE_DEVICE_NEED_REFRESH, weak=False) def attribute_updated(**kwargs): device = kwargs['device'] attribute = kwargs['attribute'] _LOGGER.debug('Update attribute for device {} {}'.format( device, attribute)) key = '{}-{}-{}-{}'.format( device.addr, attribute['endpoint'], attribute['cluster'], attribute['attribute'], ) entity = hass.data[DATA_ZIGATE_ATTRS].get(key) if entity: if entity.hass: entity.schedule_update_ha_state() key = '{}-{}-{}'.format( device.addr, 'switch', attribute['endpoint'], ) entity = hass.data[DATA_ZIGATE_ATTRS].get(key) if entity: if entity.hass: entity.schedule_update_ha_state() key = '{}-{}-{}'.format( device.addr, 'light', attribute['endpoint'], ) entity = hass.data[DATA_ZIGATE_ATTRS].get(key) if entity: if entity.hass: entity.schedule_update_ha_state() entity = hass.data[DATA_ZIGATE_DEVICES].get(device.addr) if entity: if entity.hass: entity.schedule_update_ha_state() zigate.dispatcher.connect(attribute_updated, zigate.ZIGATE_ATTRIBUTE_UPDATED, weak=False) def device_updated(**kwargs): device = kwargs['device'] _LOGGER.debug('Update device {}'.format(device)) entity = hass.data[DATA_ZIGATE_DEVICES].get(device.addr) if entity: if entity.hass: entity.schedule_update_ha_state() else: _LOGGER.debug('Device not found {}, adding it'.format(device)) device_added(device=device) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_DEVICE_UPDATED, weak=False) zigate.dispatcher.connect(device_updated, zigate.ZIGATE_ATTRIBUTE_ADDED, weak=False) def zigate_reset(service): z.reset() def permit_join(service): z.permit_join() def zigate_cleanup(service): ''' Remove missing device ''' z.cleanup_devices() def start_zigate(service_event): z.autoStart() z.start_auto_save() # firt load for device in z.devices: device_added(device=device) load_platform(hass, 'sensor', DOMAIN, {}, config) load_platform(hass, 'binary_sensor', DOMAIN, {}, config) load_platform(hass, 'switch', DOMAIN, {}, config) load_platform(hass, 'light', DOMAIN, {}, config) def stop_zigate(service_event): z.save_state() z.close() def refresh_devices_list(service): z.get_devices_list() def refresh_device(service): addr = service.data.get(ADDR) if addr: z.refresh_device(addr) else: for device in z.devices: device.refresh_device() def network_scan(service): z.start_network_scan() def raw_command(service): cmd = int(service.data.get('cmd')) data = service.data.get('data', '') z.send_data(cmd, data) def identify_device(service): addr = service.data.get('addr') z.identify_device(addr) def initiate_touchlink(service): z.initiate_touchlink() def touchlink_factory_reset(service): z.touchlink_factory_reset() 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, '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, '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, 'initiate_touchlink', initiate_touchlink) hass.services.register(DOMAIN, 'touchlink_factory_reset', touchlink_factory_reset) track_time_change(hass, refresh_devices_list, hour=0, minute=0, second=0) return True
async def async_setup(hass, config): """Set up all groups found defined in the configuration.""" if (component := hass.data.get(DOMAIN)) is None: component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)
async def async_setup(hass, config): """Set up all groups found defined in the configuration.""" component = hass.data.get(DOMAIN) if component is None: component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass) hass.data[REG_KEY] = GroupIntegrationRegistry() await async_process_integration_platforms(hass, DOMAIN, _process_group_platform) await _async_process_config(hass, config, component) async def reload_service_handler(service): """Remove all user-defined groups and load new ones from config.""" # auto = list(filter(lambda e: not e.user_defined, component.entities)) # fix for ais-dom groups defined in packages auto = list(component.entities) conf = await component.async_prepare_reload() if conf is None: return await _async_process_config(hass, conf, component) await component.async_add_entities(auto) await async_reload_integration_platforms(hass, DOMAIN, PLATFORMS) hass.services.async_register( DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=vol.Schema({}) ) service_lock = asyncio.Lock() async def locked_service_handler(service): """Handle a service with an async lock.""" async with service_lock: await groups_service_handler(service) async def groups_service_handler(service): """Handle dynamic group service functions.""" object_id = service.data[ATTR_OBJECT_ID] entity_id = f"{DOMAIN}.{object_id}" group = component.get_entity(entity_id) # new group if service.service == SERVICE_SET and group is None: entity_ids = ( service.data.get(ATTR_ENTITIES) or service.data.get(ATTR_ADD_ENTITIES) or None ) extra_arg = { attr: service.data[attr] for attr in (ATTR_ICON,) if service.data.get(attr) is not None } await Group.async_create_group( hass, service.data.get(ATTR_NAME, object_id), object_id=object_id, entity_ids=entity_ids, user_defined=False, mode=service.data.get(ATTR_ALL), **extra_arg, ) return if group is None: _LOGGER.warning("%s:Group '%s' doesn't exist!", service.service, object_id) return # update group if service.service == SERVICE_SET: need_update = False if ATTR_ADD_ENTITIES in service.data: delta = service.data[ATTR_ADD_ENTITIES] entity_ids = set(group.tracking) | set(delta) await group.async_update_tracked_entity_ids(entity_ids) if ATTR_ENTITIES in service.data: entity_ids = service.data[ATTR_ENTITIES] await group.async_update_tracked_entity_ids(entity_ids) if ATTR_NAME in service.data: group.name = service.data[ATTR_NAME] need_update = True if ATTR_ICON in service.data: group.icon = service.data[ATTR_ICON] need_update = True if ATTR_ALL in service.data: group.mode = all if service.data[ATTR_ALL] else any need_update = True if need_update: group.async_write_ha_state() return # remove group if service.service == SERVICE_REMOVE: await component.async_remove_entity(entity_id) hass.services.async_register( DOMAIN, SERVICE_SET, locked_service_handler, schema=vol.All( vol.Schema( { vol.Required(ATTR_OBJECT_ID): cv.slug, vol.Optional(ATTR_NAME): cv.string, vol.Optional(ATTR_ICON): cv.string, vol.Optional(ATTR_ALL): cv.boolean, vol.Exclusive(ATTR_ENTITIES, "entities"): cv.entity_ids, vol.Exclusive(ATTR_ADD_ENTITIES, "entities"): cv.entity_ids, } ) ), ) hass.services.async_register( DOMAIN, SERVICE_REMOVE, groups_service_handler, schema=vol.Schema({vol.Required(ATTR_OBJECT_ID): cv.slug}), ) return True
def async_setup(hass, config): """Expose light control via statemachine and services.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LIGHTS) yield from component.async_setup(config) # load profiles from files profiles_valid = yield from Profiles.load_profiles(hass) if not profiles_valid: return False @asyncio.coroutine def async_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.async_extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) preprocess_turn_on_alternatives(params) for light in target_lights: if service.service == SERVICE_TURN_ON: yield from light.async_turn_on(**params) elif service.service == SERVICE_TURN_OFF: yield from light.async_turn_off(**params) else: yield from light.async_toggle(**params) update_tasks = [] for light in target_lights: if not light.should_poll: continue update_coro = hass.async_add_job( light.async_update_ha_state(True)) if hasattr(light, 'async_update'): update_tasks.append(update_coro) else: yield from update_coro if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) # Listen for light on and light off service calls. descriptions = yield from hass.async_add_job( load_yaml_config_file, os.path.join( os.path.dirname(__file__), 'services.yaml')) hass.services.async_register( DOMAIN, SERVICE_TURN_ON, async_handle_light_service, descriptions.get(SERVICE_TURN_ON), schema=LIGHT_TURN_ON_SCHEMA) hass.services.async_register( DOMAIN, SERVICE_TURN_OFF, async_handle_light_service, descriptions.get(SERVICE_TURN_OFF), schema=LIGHT_TURN_OFF_SCHEMA) hass.services.async_register( DOMAIN, SERVICE_TOGGLE, async_handle_light_service, descriptions.get(SERVICE_TOGGLE), schema=LIGHT_TOGGLE_SCHEMA) 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 list(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 list(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): """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(hass, 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 async_setup(hass, config): """Expose light control via statemachine and services.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LIGHTS) yield from component.async_setup(config) # load profiles from files profiles = yield from hass.loop.run_in_executor( None, _load_profile_data, hass) if profiles is None: return False @asyncio.coroutine def async_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.async_extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) # 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: if service.service == SERVICE_TURN_ON: yield from light.async_turn_on(**params) elif service.service == SERVICE_TURN_OFF: yield from light.async_turn_off(**params) else: yield from light.async_toggle(**params) update_tasks = [] for light in target_lights: if not light.should_poll: continue update_coro = hass.loop.create_task( light.async_update_ha_state(True)) if hasattr(light, 'async_update'): update_tasks.append(update_coro) else: yield from update_coro if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) # Listen for light on and light off service calls. descriptions = yield from hass.loop.run_in_executor( None, load_yaml_config_file, os.path.join( os.path.dirname(__file__), 'services.yaml')) hass.services.async_register( DOMAIN, SERVICE_TURN_ON, async_handle_light_service, descriptions.get(SERVICE_TURN_ON), schema=LIGHT_TURN_ON_SCHEMA) hass.services.async_register( DOMAIN, SERVICE_TURN_OFF, async_handle_light_service, descriptions.get(SERVICE_TURN_OFF), schema=LIGHT_TURN_OFF_SCHEMA) hass.services.async_register( DOMAIN, SERVICE_TOGGLE, async_handle_light_service, descriptions.get(SERVICE_TOGGLE), schema=LIGHT_TOGGLE_SCHEMA) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the weather component.""" component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) await component.async_setup(config) return True
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Set up an input datetime.""" component = EntityComponent(_LOGGER, DOMAIN, hass) id_manager = collection.IDManager() yaml_collection = collection.YamlCollection( logging.getLogger(f"{__name__}.yaml_collection"), id_manager) collection.sync_entity_lifecycle(hass, DOMAIN, DOMAIN, component, yaml_collection, InputDatetime.from_yaml) storage_collection = DateTimeStorageCollection( Store(hass, STORAGE_VERSION, STORAGE_KEY), logging.getLogger(f"{__name__}.storage_collection"), id_manager, ) collection.sync_entity_lifecycle(hass, DOMAIN, DOMAIN, component, storage_collection, InputDatetime) await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in config.get(DOMAIN, {}).items()]) await storage_collection.async_load() collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS).async_setup(hass) async def reload_service_handler(service_call: ServiceCallType) -> None: """Reload yaml entities.""" conf = await component.async_prepare_reload(skip_reset=True) if conf is None: conf = {DOMAIN: {}} await yaml_collection.async_load([{ CONF_ID: id_, **cfg } for id_, cfg in conf.get(DOMAIN, {}).items()]) homeassistant.helpers.service.async_register_admin_service( hass, DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA, ) component.async_register_entity_service( "set_datetime", vol.All( vol.Schema( { vol.Optional(ATTR_DATE): cv.date, vol.Optional(ATTR_TIME): cv.time, vol.Optional(ATTR_DATETIME): cv.datetime, vol.Optional(ATTR_TIMESTAMP): vol.Coerce(float), }, extra=vol.ALLOW_EXTRA, ), cv.has_at_least_one_key(ATTR_DATE, ATTR_TIME, ATTR_DATETIME, ATTR_TIMESTAMP), validate_set_datetime_attrs, ), "async_set_datetime", ) return True
def setup(hass, config): """Expose light control via statemachine and services.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL, 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
async def async_setup(hass, config): """Track states and offer events for sensors.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) await component.async_setup(config) return True
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Set up an input slider.""" component = EntityComponent(_LOGGER, DOMAIN, hass) id_manager = collection.IDManager() yaml_collection = collection.YamlCollection( logging.getLogger(f"{__name__}.yaml_collection"), id_manager) collection.attach_entity_component_collection( component, yaml_collection, lambda cfg: TemplateNumber.from_yaml(cfg, hass)) storage_collection = NumberStorageCollection( Store(hass, STORAGE_VERSION, STORAGE_KEY), logging.getLogger(f"{__name__}.storage_collection"), id_manager, ) collection.attach_entity_component_collection(component, storage_collection, TemplateNumber) await yaml_collection.async_load([{ CONF_ID: id_, **(conf or {}) } for id_, conf in config.get(DOMAIN, {}).items()]) await storage_collection.async_load() collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS).async_setup(hass) collection.attach_entity_registry_cleaner(hass, DOMAIN, DOMAIN, yaml_collection) collection.attach_entity_registry_cleaner(hass, DOMAIN, DOMAIN, storage_collection) async def reload_service_handler(service_call: ServiceCallType) -> None: """Reload yaml entities.""" conf = await component.async_prepare_reload(skip_reset=True) if conf is None: conf = {DOMAIN: {}} await yaml_collection.async_load([{ CONF_ID: id_, **conf } for id_, conf in conf.get(DOMAIN, {}).items()]) homeassistant.helpers.service.async_register_admin_service( hass, DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA, ) component.async_register_entity_service( SERVICE_SET_VALUE, {vol.Required(ATTR_VALUE): vol.Coerce(float)}, "async_set_value", ) component.async_register_entity_service(SERVICE_INCREMENT, {}, "async_increment") component.async_register_entity_service(SERVICE_DECREMENT, {}, "async_decrement") # (Start) Template Number component.async_register_entity_service( SERVICE_SET_VALUE_NO_SCRIPT, {vol.Required(ATTR_VALUE): vol.Coerce(float)}, "async_set_value_no_script", ) # (End) Template Number return True