def setup(hass, config): """ Track states and offer events for switches. """ component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, GROUP_NAME_ALL_SWITCHES) component.setup(config) def handle_switch_service(service): """ Handles 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() else: switch.turn_off() if switch.should_poll: switch.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service) hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service) return True
def setup(hass, config): """Set up the Remember the milk component.""" component = EntityComponent(_LOGGER, DOMAIN, hass, group_name=GROUP_NAME_RTM) stored_rtm_config = RememberTheMilkConfiguration(hass) for rtm_config in config[DOMAIN]: account_name = rtm_config[CONF_NAME] _LOGGER.info("Adding Remember the milk account %s", account_name) api_key = rtm_config[CONF_API_KEY] shared_secret = rtm_config[CONF_SHARED_SECRET] token = stored_rtm_config.get_token(account_name) if token: _LOGGER.debug("found token for account %s", account_name) _create_instance(hass, account_name, api_key, shared_secret, token, stored_rtm_config, component) else: _register_new_account(hass, account_name, api_key, shared_secret, stored_rtm_config, component) _LOGGER.debug("Finished adding all Remember the milk accounts") return True
async def test_set_entity_namespace_via_config(hass): """Test setting an entity namespace.""" def platform_setup(hass, config, add_entities, discovery_info=None): """Test the platform setup.""" add_entities([MockEntity(name="beer"), MockEntity(name=None)]) platform = MockPlatform(platform_setup) mock_entity_platform(hass, "test_domain.platform", platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component.setup( {DOMAIN: { "platform": "platform", "entity_namespace": "yummy" }}) await hass.async_block_till_done() assert sorted(hass.states.async_entity_ids()) == [ "test_domain.yummy_beer", "test_domain.yummy_unnamed_device", ]
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()) async_track_time_interval(hass, 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) for camera in target_cameras: try: if service.service == SERVICE_ARM: yield from camera.async_arm() elif service.service == SERVICE_DISARM: yield from camera.async_disarm() except AttributeError: pass update_tasks = [] for camera in target_cameras: if not camera.should_poll: continue update_coro = hass.async_add_job( camera.async_update_ha_state(True)) if hasattr(camera, 'async_update'): update_tasks.append(update_coro) else: yield from update_coro 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_ARM, async_handle_camera_service, descriptions.get(SERVICE_ARM), schema=CAMERA_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_DISARM, async_handle_camera_service, descriptions.get(SERVICE_DISARM), schema=CAMERA_SERVICE_SCHEMA) return True
def _async_get_component(hass: HomeAssistant) -> EntityComponent: if (component := hass.data.get(DOMAIN)) is None: component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)
def async_setup(hass, config): """Setup the automation.""" component = EntityComponent(_LOGGER, DOMAIN, hass, group_name=GROUP_NAME_ALL_AUTOMATIONS) success = yield from _async_process_config(hass, config, component) if not success: return False descriptions = yield from hass.loop.run_in_executor( None, conf_util.load_yaml_config_file, os.path.join(os.path.dirname(__file__), 'services.yaml')) @asyncio.coroutine def trigger_service_handler(service_call): """Handle automation triggers.""" tasks = [] for entity in component.async_extract_from_service(service_call): tasks.append( entity.async_trigger(service_call.data.get(ATTR_VARIABLES), True)) if tasks: yield from asyncio.wait(tasks, loop=hass.loop) @asyncio.coroutine def turn_onoff_service_handler(service_call): """Handle automation turn on/off service calls.""" tasks = [] method = 'async_{}'.format(service_call.service) for entity in component.async_extract_from_service(service_call): tasks.append(getattr(entity, method)()) if tasks: yield from asyncio.wait(tasks, loop=hass.loop) @asyncio.coroutine def toggle_service_handler(service_call): """Handle automation toggle service calls.""" tasks = [] for entity in 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: yield from asyncio.wait(tasks, loop=hass.loop) @asyncio.coroutine def reload_service_handler(service_call): """Remove all automations and load new ones from config.""" conf = yield from component.async_prepare_reload() if conf is None: return yield from _async_process_config(hass, conf, component) hass.services.async_register(DOMAIN, SERVICE_TRIGGER, trigger_service_handler, descriptions.get(SERVICE_TRIGGER), schema=TRIGGER_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_RELOAD, reload_service_handler, descriptions.get(SERVICE_RELOAD), schema=RELOAD_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TOGGLE, toggle_service_handler, descriptions.get(SERVICE_TOGGLE), schema=SERVICE_SCHEMA) for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF): hass.services.async_register(DOMAIN, service, turn_onoff_service_handler, descriptions.get(service), schema=SERVICE_SCHEMA) return True
def setup(hass, config): """Track states and offer events for media_players.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def media_player_service_handler(service): """Map services to methods on MediaPlayerDevice.""" method = SERVICE_TO_METHOD[service.service] for player in component.extract_from_service(service): getattr(player, method)() if player.should_poll: player.update_ha_state(True) for service in SERVICE_TO_METHOD: hass.services.register(DOMAIN, service, media_player_service_handler, descriptions.get(service), schema=MEDIA_PLAYER_SCHEMA) def volume_set_service(service): """Set specified volume on the media player.""" volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) for player in component.extract_from_service(service): player.set_volume_level(volume) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service, descriptions.get(SERVICE_VOLUME_SET), schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA) def volume_mute_service(service): """Mute (true) or unmute (false) the media player.""" mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED) for player in component.extract_from_service(service): player.mute_volume(mute) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service, descriptions.get(SERVICE_VOLUME_MUTE), schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA) def media_seek_service(service): """Seek to a position.""" position = service.data.get(ATTR_MEDIA_SEEK_POSITION) for player in component.extract_from_service(service): player.media_seek(position) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service, descriptions.get(SERVICE_MEDIA_SEEK), schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA) def select_source_service(service): """Change input to selected source.""" input_source = service.data.get(ATTR_INPUT_SOURCE) for player in component.extract_from_service(service): player.select_source(input_source) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE, select_source_service, descriptions.get(SERVICE_SELECT_SOURCE), schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA) def play_media_service(service): """Play specified media_id on the media player.""" media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE) media_id = service.data.get(ATTR_MEDIA_CONTENT_ID) enqueue = service.data.get(ATTR_MEDIA_ENQUEUE) kwargs = { ATTR_MEDIA_ENQUEUE: enqueue, } for player in component.extract_from_service(service): player.play_media(media_type, media_id, **kwargs) if player.should_poll: player.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service, descriptions.get(SERVICE_PLAY_MEDIA), schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA) return True
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
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, config): """Expose light control via state machine and services.""" component = hass.data[DOMAIN] = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LIGHTS) await component.async_setup(config) # load profiles from files profiles_valid = await Profiles.load_profiles(hass) if not profiles_valid: return False async def async_handle_light_on_service(service): """Handle a turn light on service call.""" # Get the validated data params = service.data.copy() # Convert the entity ids to valid light ids target_lights = await component.async_extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) if service.context.user_id: user = await hass.auth.async_get_user(service.context.user_id) if user is None: raise UnknownUser(context=service.context) entity_perms = user.permissions.check_entity for light in target_lights: if not entity_perms(light, POLICY_CONTROL): raise Unauthorized( context=service.context, entity_id=light, permission=POLICY_CONTROL ) preprocess_turn_on_alternatives(params) turn_lights_off, off_params = preprocess_turn_off(params) update_tasks = [] for light in target_lights: light.async_set_context(service.context) pars = params off_pars = off_params turn_light_off = turn_lights_off if not pars: pars = params.copy() pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id) preprocess_turn_on_alternatives(pars) turn_light_off, off_pars = preprocess_turn_off(pars) if turn_light_off: await light.async_turn_off(**off_pars) else: await light.async_turn_on(**pars) if not light.should_poll: continue update_tasks.append( light.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks) # Listen for light on and light off service calls. hass.services.async_register( DOMAIN, SERVICE_TURN_ON, async_handle_light_on_service, schema=LIGHT_TURN_ON_SCHEMA) component.async_register_entity_service( SERVICE_TURN_OFF, LIGHT_TURN_OFF_SCHEMA, 'async_turn_off' ) component.async_register_entity_service( SERVICE_TOGGLE, LIGHT_TOGGLE_SCHEMA, 'async_toggle' ) hass.helpers.intent.async_register(SetIntentHandler()) return True
async def test_setup_entry_platform_not_exist(hass): """Test setup entry fails if platform doesnt exist.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entry = MockConfigEntry(domain='non_existing') assert (await component.async_setup_entry(entry)) is False
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( websocket_handle_thumbnail) hass.components.websocket_api.async_register_command( websocket_browse_media) hass.http.register_view(MediaPlayerImageView(component)) await component.async_setup(config) component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on", [SUPPORT_TURN_ON]) component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off", [SUPPORT_TURN_OFF]) component.async_register_entity_service( SERVICE_TOGGLE, {}, "async_toggle", [SUPPORT_TURN_OFF | SUPPORT_TURN_ON]) component.async_register_entity_service( SERVICE_VOLUME_UP, {}, "async_volume_up", [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], ) component.async_register_entity_service( SERVICE_VOLUME_DOWN, {}, "async_volume_down", [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], ) component.async_register_entity_service( SERVICE_MEDIA_PLAY_PAUSE, {}, "async_media_play_pause", [SUPPORT_PLAY | SUPPORT_PAUSE], ) component.async_register_entity_service(SERVICE_MEDIA_PLAY, {}, "async_media_play", [SUPPORT_PLAY]) component.async_register_entity_service(SERVICE_MEDIA_PAUSE, {}, "async_media_pause", [SUPPORT_PAUSE]) component.async_register_entity_service(SERVICE_MEDIA_STOP, {}, "async_media_stop", [SUPPORT_STOP]) component.async_register_entity_service(SERVICE_MEDIA_NEXT_TRACK, {}, "async_media_next_track", [SUPPORT_NEXT_TRACK]) component.async_register_entity_service( SERVICE_MEDIA_PREVIOUS_TRACK, {}, "async_media_previous_track", [SUPPORT_PREVIOUS_TRACK], ) component.async_register_entity_service(SERVICE_CLEAR_PLAYLIST, {}, "async_clear_playlist", [SUPPORT_CLEAR_PLAYLIST]) component.async_register_entity_service( SERVICE_VOLUME_SET, vol.All( cv.make_entity_service_schema( {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float}), _rename_keys(volume=ATTR_MEDIA_VOLUME_LEVEL), ), "async_set_volume_level", [SUPPORT_VOLUME_SET], ) component.async_register_entity_service( SERVICE_VOLUME_MUTE, vol.All( cv.make_entity_service_schema( {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean}), _rename_keys(mute=ATTR_MEDIA_VOLUME_MUTED), ), "async_mute_volume", [SUPPORT_VOLUME_MUTE], ) component.async_register_entity_service( SERVICE_MEDIA_SEEK, vol.All( cv.make_entity_service_schema( {vol.Required(ATTR_MEDIA_SEEK_POSITION): cv.positive_float}), _rename_keys(position=ATTR_MEDIA_SEEK_POSITION), ), "async_media_seek", [SUPPORT_SEEK], ) component.async_register_entity_service( SERVICE_SELECT_SOURCE, {vol.Required(ATTR_INPUT_SOURCE): cv.string}, "async_select_source", [SUPPORT_SELECT_SOURCE], ) component.async_register_entity_service( SERVICE_SELECT_SOUND_MODE, {vol.Required(ATTR_SOUND_MODE): cv.string}, "async_select_sound_mode", [SUPPORT_SELECT_SOUND_MODE], ) component.async_register_entity_service( SERVICE_PLAY_MEDIA, vol.All( cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA), _rename_keys( media_type=ATTR_MEDIA_CONTENT_TYPE, media_id=ATTR_MEDIA_CONTENT_ID, enqueue=ATTR_MEDIA_ENQUEUE, ), ), "async_play_media", [SUPPORT_PLAY_MEDIA], ) component.async_register_entity_service( SERVICE_SHUFFLE_SET, {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean}, "async_set_shuffle", [SUPPORT_SHUFFLE_SET], ) component.async_register_entity_service( SERVICE_REPEAT_SET, {vol.Required(ATTR_MEDIA_REPEAT): vol.In(REPEAT_MODES)}, "async_set_repeat", [SUPPORT_REPEAT_SET], ) 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): """Setup thermostats.""" component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) component.setup(config) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) def away_mode_set_service(service): """Set away mode on target thermostats.""" target_thermostats = component.extract_from_service(service) away_mode = service.data[ATTR_AWAY_MODE] for thermostat in target_thermostats: if away_mode: thermostat.turn_away_mode_on() else: thermostat.turn_away_mode_off() thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, descriptions.get(SERVICE_SET_AWAY_MODE), schema=SET_AWAY_MODE_SCHEMA) def temperature_set_service(service): """Set temperature on the target thermostats.""" target_thermostats = component.extract_from_service(service) temperature = service.data[ATTR_TEMPERATURE] for thermostat in target_thermostats: thermostat.set_temperature( convert(temperature, hass.config.temperature_unit, thermostat.unit_of_measurement)) thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE), schema=SET_TEMPERATURE_SCHEMA) def fan_mode_set_service(service): """Set fan mode on target thermostats.""" target_thermostats = component.extract_from_service(service) fan_mode = service.data[ATTR_FAN] for thermostat in target_thermostats: if fan_mode: thermostat.turn_fan_on() else: thermostat.turn_fan_off() thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, descriptions.get(SERVICE_SET_FAN_MODE), schema=SET_FAN_MODE_SCHEMA) def hvac_mode_set_service(service): """Set hvac mode on target thermostats.""" target_thermostats = component.extract_from_service(service) hvac_mode = service.data[ATTR_HVAC_MODE] for thermostat in target_thermostats: thermostat.set_hvac_mode(hvac_mode) thermostat.update_ha_state(True) hass.services.register(DOMAIN, SERVICE_SET_HVAC_MODE, hvac_mode_set_service, descriptions.get(SERVICE_SET_HVAC_MODE), schema=SET_HVAC_MODE_SCHEMA) return True
def setup(hass, config): """Set up variables.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] items = config.get(DOMAIN) if items is not None: for variable_id, variable_config in items.items(): if not variable_config: variable_config = {} name = variable_config.get(CONF_NAME) default_temp = variable_config.get(ATTR_DEFAULT_TEMP) entities.append(TemperatureControl(variable_id, name, default_temp)) def get_temperature_service(call): """Handle calls to the set_variable service.""" entity_id = ENTITY_ID_FORMAT.format(call.data.get(ATTR_CONTROLLER)) entity = component.get_entity(entity_id) if entity: return entity.get_temperature(call.data.get(CONF_TIME_STEP)) else: _LOGGER.warning("Failed to set unknown variable: %s", entity_id) def set_period_service(call): """Handle calls to the set_variable service.""" entity_id = ENTITY_ID_FORMAT.format(call.data.get(CONF_NAME)) entity = component.get_entity(entity_id) _LOGGER.warning( f'Start updating (set_period_service) period on {entity_id}') if entity: entity.set_period( call.data.get(CONF_PERIOD_ID), call.data.get(CONF_TIME_START), call.data.get(CONF_TIME_STOP), call.data.get(CONF_PERIOD_TEMP), call.data.get(CONF_DAYS), ) else: _LOGGER.warning("Failed to set unknown variable: %s", entity_id) hass.services.register( DOMAIN, SERVICE_GET_TEMPERATURE, get_temperature_service, schema=SERVICE_GET_TEMPERATURE_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_PERIOD, set_period_service, schema=SERVICE_SET_PERIOD_SCHEMA, ) component.add_entities(entities) return True
def setup(hass, config): """Set up the Wink component.""" if hass.data.get(DOMAIN) is None: hass.data[DOMAIN] = { "unique_ids": [], "entities": {}, "oauth": {}, "configuring": {}, "pubnub": None, "configurator": False, } if config.get(DOMAIN) is not None: client_id = config[DOMAIN].get(CONF_CLIENT_ID) client_secret = config[DOMAIN].get(CONF_CLIENT_SECRET) email = config[DOMAIN].get(CONF_EMAIL) password = config[DOMAIN].get(CONF_PASSWORD) local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL) else: client_id = None client_secret = None email = None password = None local_control = None hass.data[DOMAIN]["configurator"] = True if None not in [client_id, client_secret]: _LOGGER.info("Using legacy OAuth authentication") if not local_control: pywink.disable_local_control() hass.data[DOMAIN]["oauth"][CONF_CLIENT_ID] = client_id hass.data[DOMAIN]["oauth"][CONF_CLIENT_SECRET] = client_secret hass.data[DOMAIN]["oauth"]["email"] = email hass.data[DOMAIN]["oauth"]["password"] = password pywink.legacy_set_wink_credentials(email, password, client_id, client_secret) else: _LOGGER.info("Using OAuth authentication") if not local_control: pywink.disable_local_control() config_path = hass.config.path(WINK_CONFIG_FILE) if os.path.isfile(config_path): config_file = load_json(config_path) if config_file == DEFAULT_CONFIG: _request_app_setup(hass, config) return True # else move on because the user modified the file else: save_json(config_path, DEFAULT_CONFIG) _request_app_setup(hass, config) return True if DOMAIN in hass.data[DOMAIN]["configuring"]: _configurator = hass.data[DOMAIN]["configuring"] hass.components.configurator.request_done( _configurator.pop(DOMAIN)) # Using oauth access_token = config_file.get(ATTR_ACCESS_TOKEN) refresh_token = config_file.get(ATTR_REFRESH_TOKEN) # This will be called after authorizing Home-Assistant if None not in (access_token, refresh_token): pywink.set_wink_credentials( config_file.get(CONF_CLIENT_ID), config_file.get(CONF_CLIENT_SECRET), access_token=access_token, refresh_token=refresh_token, ) # This is called to create the redirect so the user can Authorize # Home . else: redirect_uri = f"{get_url(hass)}{WINK_AUTH_CALLBACK_PATH}" wink_auth_start_url = pywink.get_authorization_url( config_file.get(CONF_CLIENT_ID), redirect_uri) hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url) hass.http.register_view( WinkAuthCallbackView(config, config_file, pywink.request_token)) _request_oauth_completion(hass, config) return True pywink.set_user_agent(USER_AGENT) sub_details = pywink.get_subscription_details() hass.data[DOMAIN]["pubnub"] = PubNubSubscriptionHandler( sub_details[0], origin=sub_details[1]) def _subscribe(): hass.data[DOMAIN]["pubnub"].subscribe() # Call subscribe after the user sets up wink via the configurator # All other methods will complete setup before # EVENT_HOMEASSISTANT_START is called meaning they # will call subscribe via the method below. (start_subscription) if hass.data[DOMAIN]["configurator"]: _subscribe() def keep_alive_call(event_time): """Call the Wink API endpoints to keep PubNub working.""" _LOGGER.info("Polling the Wink API to keep PubNub updates flowing") pywink.set_user_agent(str(int(time.time()))) _temp_response = pywink.get_user() _LOGGER.debug(str(json.dumps(_temp_response))) time.sleep(1) pywink.set_user_agent(USER_AGENT) _temp_response = pywink.wink_api_fetch() _LOGGER.debug("%s", _temp_response) _temp_response = pywink.post_session() _LOGGER.debug("%s", _temp_response) # Call the Wink API every hour to keep PubNub updates flowing track_time_interval(hass, keep_alive_call, timedelta(minutes=60)) def start_subscription(event): """Start the PubNub subscription.""" _subscribe() hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription) def stop_subscription(event): """Stop the PubNub subscription.""" hass.data[DOMAIN]["pubnub"].unsubscribe() hass.data[DOMAIN]["pubnub"] = None hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription) def save_credentials(event): """Save currently set OAuth credentials.""" if hass.data[DOMAIN]["oauth"].get("email") is None: config_path = hass.config.path(WINK_CONFIG_FILE) _config = pywink.get_current_oauth_credentials() save_json(config_path, _config) hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials) # Save the users potentially updated oauth credentials at a regular # interval to prevent them from being expired after a HA reboot. track_time_interval(hass, save_credentials, timedelta(minutes=60)) def force_update(call): """Force all devices to poll the Wink API.""" _LOGGER.info("Refreshing Wink states from API") for entity_list in hass.data[DOMAIN]["entities"].values(): # Throttle the calls to Wink API for entity in entity_list: time.sleep(1) entity.schedule_update_ha_state(True) hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update) def pull_new_devices(call): """Pull new devices added to users Wink account since startup.""" _LOGGER.info("Getting new devices from Wink API") for _component in WINK_COMPONENTS: discovery.load_platform(hass, _component, DOMAIN, {}, config) hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices) def set_pairing_mode(call): """Put the hub in provided pairing mode.""" hub_name = call.data.get("hub_name") pairing_mode = call.data.get("pairing_mode") kidde_code = call.data.get("kidde_radio_code") for hub in WINK_HUBS: if hub.name() == hub_name: hub.pair_new_device(pairing_mode, kidde_radio_code=kidde_code) def rename_device(call): """Set specified device's name.""" # This should only be called on one device at a time. found_device = None entity_id = call.data.get("entity_id")[0] all_devices = [] for list_of_devices in hass.data[DOMAIN]["entities"].values(): all_devices += list_of_devices for device in all_devices: if device.entity_id == entity_id: found_device = device if found_device is not None: name = call.data.get("name") found_device.wink.set_name(name) hass.services.register(DOMAIN, SERVICE_RENAME_DEVICE, rename_device, schema=RENAME_DEVICE_SCHEMA) def delete_device(call): """Delete specified device.""" # This should only be called on one device at a time. found_device = None entity_id = call.data.get("entity_id")[0] all_devices = [] for list_of_devices in hass.data[DOMAIN]["entities"].values(): all_devices += list_of_devices for device in all_devices: if device.entity_id == entity_id: found_device = device if found_device is not None: found_device.wink.remove_device() hass.services.register(DOMAIN, SERVICE_DELETE_DEVICE, delete_device, schema=DELETE_DEVICE_SCHEMA) hubs = pywink.get_hubs() for hub in hubs: if hub.device_manufacturer() == "wink": WINK_HUBS.append(hub) if WINK_HUBS: hass.services.register( DOMAIN, SERVICE_SET_PAIRING_MODE, set_pairing_mode, schema=SET_PAIRING_MODE_SCHEMA, ) def nimbus_service_handle(service): """Handle nimbus services.""" entity_id = service.data.get("entity_id")[0] _all_dials = [] for sensor in hass.data[DOMAIN]["entities"]["sensor"]: if isinstance(sensor, WinkNimbusDialDevice): _all_dials.append(sensor) for _dial in _all_dials: if _dial.entity_id == entity_id: if service.service == SERVICE_SET_DIAL_CONFIG: _dial.set_configuration(**service.data) if service.service == SERVICE_SET_DIAL_STATE: _dial.wink.set_state(service.data.get("value"), service.data.get("labels")) def siren_service_handle(service): """Handle siren services.""" entity_ids = service.data.get("entity_id") all_sirens = [] for switch in hass.data[DOMAIN]["entities"]["switch"]: if isinstance(switch, WinkSirenDevice): all_sirens.append(switch) sirens_to_set = [] if entity_ids is None: sirens_to_set = all_sirens else: for siren in all_sirens: if siren.entity_id in entity_ids: sirens_to_set.append(siren) for siren in sirens_to_set: _man = siren.wink.device_manufacturer() if (service.service != SERVICE_SET_AUTO_SHUTOFF and service.service != SERVICE_ENABLE_SIREN and _man not in ("dome", "wink")): _LOGGER.error("Service only valid for Dome or Wink sirens") return if service.service == SERVICE_ENABLE_SIREN: siren.wink.set_state(service.data.get(ATTR_ENABLED)) elif service.service == SERVICE_SET_AUTO_SHUTOFF: siren.wink.set_auto_shutoff( service.data.get(ATTR_AUTO_SHUTOFF)) elif service.service == SERVICE_SET_CHIME_VOLUME: siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME)) elif service.service == SERVICE_SET_SIREN_VOLUME: siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME)) elif service.service == SERVICE_SET_SIREN_TONE: siren.wink.set_siren_sound(service.data.get(ATTR_TONE)) elif service.service == SERVICE_ENABLE_CHIME: siren.wink.set_chime(service.data.get(ATTR_TONE)) elif service.service == SERVICE_SIREN_STROBE_ENABLED: siren.wink.set_siren_strobe_enabled( service.data.get(ATTR_ENABLED)) elif service.service == SERVICE_CHIME_STROBE_ENABLED: siren.wink.set_chime_strobe_enabled( service.data.get(ATTR_ENABLED)) # Load components for the devices in Wink that we support for wink_component in WINK_COMPONENTS: hass.data[DOMAIN]["entities"][wink_component] = [] discovery.load_platform(hass, wink_component, DOMAIN, {}, config) component = EntityComponent(_LOGGER, DOMAIN, hass) sirens = [] has_dome_or_wink_siren = False for siren in pywink.get_sirens(): _man = siren.device_manufacturer() if _man in ("dome", "wink"): has_dome_or_wink_siren = True _id = siren.object_id() + siren.name() if _id not in hass.data[DOMAIN]["unique_ids"]: sirens.append(WinkSirenDevice(siren, hass)) if sirens: hass.services.register( DOMAIN, SERVICE_SET_AUTO_SHUTOFF, siren_service_handle, schema=SET_AUTO_SHUTOFF_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_ENABLE_SIREN, siren_service_handle, schema=ENABLED_SIREN_SCHEMA, ) if has_dome_or_wink_siren: hass.services.register( DOMAIN, SERVICE_SET_SIREN_TONE, siren_service_handle, schema=SET_SIREN_TONE_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_ENABLE_CHIME, siren_service_handle, schema=SET_CHIME_MODE_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_SIREN_VOLUME, siren_service_handle, schema=SET_VOLUME_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_CHIME_VOLUME, siren_service_handle, schema=SET_VOLUME_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SIREN_STROBE_ENABLED, siren_service_handle, schema=SET_STROBE_ENABLED_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_CHIME_STROBE_ENABLED, siren_service_handle, schema=SET_STROBE_ENABLED_SCHEMA, ) component.add_entities(sirens) nimbi = [] dials = {} all_nimbi = pywink.get_cloud_clocks() all_dials = [] for nimbus in all_nimbi: if nimbus.object_type() == "cloud_clock": nimbi.append(nimbus) dials[nimbus.object_id()] = [] for nimbus in all_nimbi: if nimbus.object_type() == "dial": dials[nimbus.parent_id()].append(nimbus) for nimbus in nimbi: for dial in dials[nimbus.object_id()]: all_dials.append(WinkNimbusDialDevice(nimbus, dial, hass)) if nimbi: hass.services.register( DOMAIN, SERVICE_SET_DIAL_CONFIG, nimbus_service_handle, schema=DIAL_CONFIG_SCHEMA, ) hass.services.register( DOMAIN, SERVICE_SET_DIAL_STATE, nimbus_service_handle, schema=DIAL_STATE_SCHEMA, ) component.add_entities(all_dials) return True
def setup(hass, config): """Set up Z-Wave. Will automatically load components to support devices found on the network. """ descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) device_config = EntityValues(config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) new_entity_ids = config[DOMAIN][CONF_NEW_ENTITY_IDS] if not new_entity_ids: _LOGGER.warning( "ZWave entity_ids will soon be changing. To opt in to new " "entity_ids now, set `new_entity_ids: true` under zwave in your " "configuration.yaml. See the following blog post for details: " "https://home-assistant.io/blog/2017/06/15/zwave-entity-ids/") # Setup options options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get(CONF_CONFIG_PATH)) options.set_console_output(use_debug) if CONF_NETWORK_KEY in config[DOMAIN]: options.addOption("NetworkKey", config[DOMAIN][CONF_NETWORK_KEY]) options.lock() network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_DEVICES] = {} hass.data[DATA_ENTITY_VALUES] = [] if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Handle new added value to a node on the network.""" # Check if this value should be tracked by an existing entity for values in hass.data[DATA_ENTITY_VALUES]: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues(hass, schema, value, config, device_config) # We create a new list and update the reference here so that # the list can be safely iterated over in the main thread new_values = hass.data[DATA_ENTITY_VALUES] + [values] hass.data[DATA_ENTITY_VALUES] = new_values component = EntityComponent(_LOGGER, DOMAIN, hass) def node_added(node): """Handle a new node on the network.""" entity = ZWaveNodeEntity(node, network, new_entity_ids) name = node_name(node) if new_entity_ids: generated_id = generate_entity_id(DOMAIN + '.{}', name, []) else: generated_id = entity.entity_id node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring node entity %s due to device settings", generated_id) return component.add_entities([entity]) def network_ready(): """Handle the query of all awake nodes.""" _LOGGER.info("Zwave network is ready for use. All awake nodes " "have been queried. Sleeping nodes will be " "queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Handle the querying of all nodes on network.""" _LOGGER.info("Z-Wave network is complete. All nodes on the network " "have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect(value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect(network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect(network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Z-Wave add_node have been initialized") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Z-Wave add_node_secure have been initialized") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Z-Wwave remove_node have been initialized") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running Z-Wave command") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("Z-Wave heal running") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Z-Wave soft_reset have been initialized") network.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Z-Wave test_network have been initialized") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping Z-Wave network") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info("Renamed Z-Wave node %d to %s", node_id, name) def rename_value(service): """Rename a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] name = service.data.get(const.ATTR_NAME) value.label = name _LOGGER.info("Renamed Z-Wave value (Node %d Value %d) to %s", node_id, value_id, name) def set_poll_intensity(service): """Set the polling intensity of a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] intensity = service.data.get(const.ATTR_POLL_INTENSITY) if intensity == 0: if value.disable_poll(): _LOGGER.info("Polling disabled (Node %d Value %d)", node_id, value_id) return _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id, value_id) else: if value.enable_poll(intensity): _LOGGER.info("Set polling intensity (Node %d Value %d) to %s", node_id, value_id, intensity) return _LOGGER.info("Set polling intensity failed (Node %d Value %d)", node_id, value_id) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to remove zwave node %d", node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to replace zwave node %d", node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE) for value in (node.get_values( class_id=const.COMMAND_CLASS_CONFIGURATION).values()): if value.index != param: continue if value.type in [const.TYPE_LIST, const.TYPE_BOOL]: value.data = selection _LOGGER.info( "Setting config list parameter %s on Node %s " "with selection %s", param, node_id, selection) return value.data = int(selection) _LOGGER.info( "Setting config parameter %s on Node %s " "with selection %s", param, node_id, selection) return node.set_config_param(param, selection, size) _LOGGER.info( "Setting unknown config parameter %s on Node %s " "with selection %s", param, node_id, selection) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info( "Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info( "Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) @asyncio.coroutine def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send(hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def reset_node_meters(service): """Reset meter counters of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) instance = service.data.get(const.ATTR_INSTANCE) node = network.nodes[node_id] for value in (node.get_values( class_id=const.COMMAND_CLASS_METER).values()): if value.index != const.INDEX_METER_RESET: continue if value.instance != instance: continue network.manager.pressButton(value.value_id) network.manager.releaseButton(value.value_id) _LOGGER.info("Resetting meters on node %s instance %s....", node_id, instance) return _LOGGER.info( "Node %s on instance %s does not have resettable " "meters.", node_id, instance) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting Z-Wave network...") network.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug("network state: %d %s", network.state, network.state_str) if network.state >= network.STATE_AWAKED: _LOGGER.info("Z-Wave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info("final network state: %d %s", network.state, network.state_str) polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, descriptions[const.SERVICE_RENAME_VALUE], schema=RENAME_VALUE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, descriptions[const.SERVICE_REMOVE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, descriptions[const.SERVICE_REPLACE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[const.SERVICE_PRINT_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, descriptions[const.SERVICE_REFRESH_ENTITY], schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, descriptions[const.SERVICE_REFRESH_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, descriptions[const.SERVICE_RESET_NODE_METERS], schema=RESET_NODE_METERS_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_POLL_INTENSITY, set_poll_intensity, descriptions[const.SERVICE_SET_POLL_INTENSITY], schema=SET_POLL_INTENSITY_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("Z-Wave network autoheal is enabled") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
async def async_setup_entry(hass, config_entry): """Set up Z-Wave from a config entry. Will automatically load components to support devices found on the network. """ from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup config = {} if DATA_ZWAVE_CONFIG in hass.data: config = hass.data[DATA_ZWAVE_CONFIG] # Load configuration use_debug = config.get(CONF_DEBUG, DEFAULT_DEBUG) autoheal = config.get(CONF_AUTOHEAL, DEFAULT_CONF_AUTOHEAL) device_config = EntityValues(config.get(CONF_DEVICE_CONFIG), config.get(CONF_DEVICE_CONFIG_DOMAIN), config.get(CONF_DEVICE_CONFIG_GLOB)) # Setup options options = ZWaveOption(config_entry.data[CONF_USB_STICK_PATH], user_path=hass.config.config_dir, config_path=config.get(CONF_CONFIG_PATH)) options.set_console_output(use_debug) if config_entry.data.get(CONF_NETWORK_KEY): options.addOption("NetworkKey", config_entry.data[CONF_NETWORK_KEY]) await hass.async_add_executor_job(options.lock) network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_DEVICES] = {} hass.data[DATA_ENTITY_VALUES] = [] if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in ( ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED_SOME_DEAD): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Handle new added value to a node on the network.""" # Check if this value should be tracked by an existing entity for values in hass.data[DATA_ENTITY_VALUES]: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues(hass, schema, value, config, device_config, registry) # We create a new list and update the reference here so that # the list can be safely iterated over in the main thread new_values = hass.data[DATA_ENTITY_VALUES] + [values] hass.data[DATA_ENTITY_VALUES] = new_values component = EntityComponent(_LOGGER, DOMAIN, hass) registry = await async_get_registry(hass) def node_added(node): """Handle a new node on the network.""" entity = ZWaveNodeEntity(node, network) def _add_node_to_component(): if hass.data[DATA_DEVICES].get(entity.unique_id): return name = node_name(node) generated_id = generate_entity_id(DOMAIN + '.{}', name, []) node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring node entity %s due to device settings", generated_id) return hass.data[DATA_DEVICES][entity.unique_id] = entity component.add_entities([entity]) if entity.unique_id: _add_node_to_component() return @callback def _on_ready(sec): _LOGGER.info("Z-Wave node %d ready after %d seconds", entity.node_id, sec) hass.async_add_job(_add_node_to_component) @callback def _on_timeout(sec): _LOGGER.warning( "Z-Wave node %d not ready after %d seconds, " "continuing anyway", entity.node_id, sec) hass.async_add_job(_add_node_to_component) hass.add_job(check_has_unique_id, entity, _on_ready, _on_timeout, hass.loop) def network_ready(): """Handle the query of all awake nodes.""" _LOGGER.info("Zwave network is ready for use. All awake nodes " "have been queried. Sleeping nodes will be " "queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Handle the querying of all nodes on network.""" _LOGGER.info("Z-Wave network is complete. All nodes on the network " "have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) def network_complete_some_dead(): """Handle the querying of all nodes on network.""" _LOGGER.info("Z-Wave network is complete. All nodes on the network " "have been queried, but some nodes are marked dead") hass.bus.fire(const.EVENT_NETWORK_COMPLETE_SOME_DEAD) dispatcher.connect(value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect(network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect(network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) dispatcher.connect(network_complete_some_dead, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED_SOME_DEAD, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Z-Wave add_node have been initialized") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Z-Wave add_node_secure have been initialized") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Z-Wave remove_node have been initialized") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running Z-Wave command") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("Z-Wave heal running") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Z-Wave soft_reset have been initialized") network.controller.soft_reset() def update_config(service): """Update the config from git.""" _LOGGER.info("Configuration update has been initialized") network.controller.update_ozw_config() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Z-Wave test_network have been initialized") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping Z-Wave network") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info("Renamed Z-Wave node %d to %s", node_id, name) def rename_value(service): """Rename a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] name = service.data.get(const.ATTR_NAME) value.label = name _LOGGER.info("Renamed Z-Wave value (Node %d Value %d) to %s", node_id, value_id, name) def set_poll_intensity(service): """Set the polling intensity of a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] intensity = service.data.get(const.ATTR_POLL_INTENSITY) if intensity == 0: if value.disable_poll(): _LOGGER.info("Polling disabled (Node %d Value %d)", node_id, value_id) return _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id, value_id) else: if value.enable_poll(intensity): _LOGGER.info("Set polling intensity (Node %d Value %d) to %s", node_id, value_id, intensity) return _LOGGER.info("Set polling intensity failed (Node %d Value %d)", node_id, value_id) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to remove zwave node %d", node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to replace zwave node %d", node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE) for value in (node.get_values( class_id=const.COMMAND_CLASS_CONFIGURATION).values()): if value.index != param: continue if value.type in [const.TYPE_LIST, const.TYPE_BOOL]: value.data = str(selection) _LOGGER.info( "Setting config parameter %s on Node %s " "with list/bool selection %s", param, node_id, str(selection)) return if value.type == const.TYPE_BUTTON: network.manager.pressButton(value.value_id) network.manager.releaseButton(value.value_id) _LOGGER.info( "Setting config parameter %s on Node %s " "with button selection %s", param, node_id, selection) return value.data = int(selection) _LOGGER.info( "Setting config parameter %s on Node %s " "with selection %s", param, node_id, selection) return node.set_config_param(param, selection, size) _LOGGER.info( "Setting unknown config parameter %s on Node %s " "with selection %s", param, node_id, selection) def refresh_node_value(service): """Refresh the specified value from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] node.values[value_id].refresh() _LOGGER.info("Node %s value %s refreshed", node_id, value_id) def set_node_value(service): """Set the specified value on a node.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) value = service.data.get(const.ATTR_CONFIG_VALUE) node = network.nodes[node_id] node.values[value_id].data = value _LOGGER.info("Node %s value %s set to %s", node_id, value_id, value) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info( "Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info( "Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) async def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send(hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def reset_node_meters(service): """Reset meter counters of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) instance = service.data.get(const.ATTR_INSTANCE) node = network.nodes[node_id] for value in (node.get_values( class_id=const.COMMAND_CLASS_METER).values()): if value.index != const.INDEX_METER_RESET: continue if value.instance != instance: continue network.manager.pressButton(value.value_id) network.manager.releaseButton(value.value_id) _LOGGER.info("Resetting meters on node %s instance %s....", node_id, instance) return _LOGGER.info( "Node %s on instance %s does not have resettable " "meters.", node_id, instance) def heal_node(service): """Heal a node on the network.""" node_id = service.data.get(const.ATTR_NODE_ID) update_return_routes = service.data.get(const.ATTR_RETURN_ROUTES) node = network.nodes[node_id] _LOGGER.info("Z-Wave node heal running for node %s", node_id) node.heal(update_return_routes) def test_node(service): """Send test messages to a node on the network.""" node_id = service.data.get(const.ATTR_NODE_ID) messages = service.data.get(const.ATTR_MESSAGES) node = network.nodes[node_id] _LOGGER.info("Sending %s test-messages to node %s.", messages, node_id) node.test(messages) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting Z-Wave network...") network.start() hass.bus.fire(const.EVENT_NETWORK_START) async def _check_awaked(): """Wait for Z-wave awaked state (or timeout) and finalize start.""" _LOGGER.debug("network state: %d %s", network.state, network.state_str) start_time = dt_util.utcnow() while True: waited = int((dt_util.utcnow() - start_time).total_seconds()) if network.state >= network.STATE_AWAKED: # Need to be in STATE_AWAKED before talking to nodes. _LOGGER.info("Z-Wave ready after %d seconds", waited) break elif waited >= const.NETWORK_READY_WAIT_SECS: # Wait up to NETWORK_READY_WAIT_SECS seconds for the Z-Wave # network to be ready. _LOGGER.warning( "Z-Wave not ready after %d seconds, continuing anyway", waited) _LOGGER.info("final network state: %d %s", network.state, network.state_str) break else: await asyncio.sleep(1, loop=hass.loop) hass.async_add_job(_finalize_start) hass.add_job(_check_awaked) def _finalize_start(): """Perform final initializations after Z-Wave network is awaked.""" polling_interval = convert(config.get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset) hass.services.register(DOMAIN, const.SERVICE_UPDATE_CONFIG, update_config) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, schema=RENAME_VALUE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_NODE_VALUE, set_node_value, schema=SET_NODE_VALUE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE_VALUE, refresh_node_value, schema=REFRESH_NODE_VALUE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, schema=RESET_NODE_METERS_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_POLL_INTENSITY, set_poll_intensity, schema=SET_POLL_INTENSITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_HEAL_NODE, heal_node, schema=HEAL_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_TEST_NODE, test_node, schema=TEST_NODE_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("Z-Wave network autoheal is enabled") async_track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_zwave) hass.services.async_register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave) for entry_component in SUPPORTED_PLATFORMS: hass.async_create_task( hass.config_entries.async_forward_entry_setup( config_entry, entry_component)) 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) 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)) 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
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up an input slider.""" component = EntityComponent(_LOGGER, DOMAIN, hass) # Process integration platforms right away since # we will create entities before firing EVENT_COMPONENT_LOADED await async_process_integration_platform_for_component(hass, DOMAIN) 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, InputNumber.from_yaml ) storage_collection = NumberStorageCollection( Store(hass, STORAGE_VERSION, STORAGE_KEY), logging.getLogger(f"{__name__}.storage_collection"), id_manager, ) collection.sync_entity_lifecycle( hass, DOMAIN, DOMAIN, component, storage_collection, InputNumber ) 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) async def reload_service_handler(service_call: ServiceCall) -> 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") return True
async def test_using_prescribed_entity_id(hass): """Test for using predefined entity ID.""" component = EntityComponent(_LOGGER, DOMAIN, hass) await component.async_add_entities( [MockEntity(name="bla", entity_id="hello.world")]) assert "hello.world" in hass.states.async_entity_ids()
async def async_setup(hass, config): """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: HomeAssistant, config: ConfigType) -> bool: """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( ws_camera_web_rtc_offer) 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(_event: Event) -> None: for camera in component.entities: camera = cast(Camera, camera) camera_prefs = prefs.get(camera.entity_id) if not camera_prefs.preload_stream: continue stream = await camera.async_create_stream() if not stream: continue stream.keepalive = True stream.add_provider("hls") stream.start() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, preload_stream) @callback def update_tokens(time: datetime) -> None: """Update tokens of the entities.""" for entity in component.entities: entity = cast(Camera, entity) 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, {}, "async_enable_motion_detection") component.async_register_entity_service(SERVICE_DISABLE_MOTION, {}, "async_disable_motion_detection") component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") component.async_register_entity_service(SERVICE_TURN_ON, {}, "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: HomeAssistant, config: ConfigType) -> bool: # noqa: C901 """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 (not params or not light.is_on) or (params and ATTR_TRANSITION not in params): profiles.apply_default(light.entity_id, light.is_on, params) legacy_supported_color_modes = ( light._light_internal_supported_color_modes # pylint: disable=protected-access ) 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: if (ColorMode.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 temperature is specified, emulate it if not supported by the light if ATTR_COLOR_TEMP in params: if (supported_color_modes and ColorMode.COLOR_TEMP not in supported_color_modes and ColorMode.RGBWW in supported_color_modes): color_temp = params.pop(ATTR_COLOR_TEMP) brightness = params.get(ATTR_BRIGHTNESS, light.brightness) params[ ATTR_RGBWW_COLOR] = color_util.color_temperature_to_rgbww( color_temp, brightness, light.min_mireds, light.max_mireds) elif ColorMode.COLOR_TEMP not in legacy_supported_color_modes: color_temp = params.pop(ATTR_COLOR_TEMP) if color_supported(legacy_supported_color_modes): temp_k = color_util.color_temperature_mired_to_kelvin( color_temp) params[ATTR_HS_COLOR] = color_util.color_temperature_to_hs( temp_k) # 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) elif (rgbw_color := params.pop(ATTR_RGBW_COLOR, None)) is not None: rgb_color = color_util.color_rgbw_to_rgb(*rgbw_color) params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
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 = f"async_{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 a input_label.""" component = EntityComponent(_LOGGER, DOMAIN, hass) entities = [] for object_id, cfg in config[DOMAIN].items(): if not cfg: cfg = {} name = cfg.get(CONF_NAME) value = cfg.get(ATTR_VALUE) icon = cfg.get(CONF_ICON) readonly = cfg.get(ATTR_READONLY) entities.append(GlobalLabelData(object_id, name, value, icon, readonly)) if not entities: return False @asyncio.coroutine def async_handler_service(service): """Handle a call to the input_label services.""" target_global_labels = component.async_extract_from_service(service) if service.service == SERVICE_SETVALUE: attr = 'async_set_value' elif service.service == SERVICE_SETNAME: attr = 'async_set_name' else: attr = "async_set_icon" tasks = [ getattr(global_label, attr)(service.data[ATTR_VALUE]) for global_label in target_global_labels ] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) descriptions = yield from hass.async_add_job( load_yaml_config_file, os.path.join(os.path.dirname(__file__), 'services.yaml')) hass.services.async_register(DOMAIN, SERVICE_SETVALUE, async_handler_service, descriptions[DOMAIN][SERVICE_SETVALUE], SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_SETICON, async_handler_service, descriptions[DOMAIN][SERVICE_SETICON], SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_SETNAME, async_handler_service, descriptions[DOMAIN][SERVICE_SETNAME], SERVICE_SCHEMA) yield from component.async_add_entities(entities) 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)) # 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) hass.services.async_register(DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_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 = 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, 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_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 ATTR_ALL in service.data: group.mode = all if service.data[ATTR_ALL] else any 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, locked_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 await 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: """Track states and offer events for media_players.""" component = hass.data[DOMAIN] = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) websocket_api.async_register_command(hass, websocket_browse_media) hass.http.register_view(MediaPlayerImageView(component)) await component.async_setup(config) component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on", [MediaPlayerEntityFeature.TURN_ON]) component.async_register_entity_service( SERVICE_TURN_OFF, {}, "async_turn_off", [MediaPlayerEntityFeature.TURN_OFF]) component.async_register_entity_service( SERVICE_TOGGLE, {}, "async_toggle", [MediaPlayerEntityFeature.TURN_OFF | MediaPlayerEntityFeature.TURN_ON], ) component.async_register_entity_service( SERVICE_VOLUME_UP, {}, "async_volume_up", [ MediaPlayerEntityFeature.VOLUME_SET, MediaPlayerEntityFeature.VOLUME_STEP ], ) component.async_register_entity_service( SERVICE_VOLUME_DOWN, {}, "async_volume_down", [ MediaPlayerEntityFeature.VOLUME_SET, MediaPlayerEntityFeature.VOLUME_STEP ], ) component.async_register_entity_service( SERVICE_MEDIA_PLAY_PAUSE, {}, "async_media_play_pause", [MediaPlayerEntityFeature.PLAY | MediaPlayerEntityFeature.PAUSE], ) component.async_register_entity_service(SERVICE_MEDIA_PLAY, {}, "async_media_play", [MediaPlayerEntityFeature.PLAY]) component.async_register_entity_service(SERVICE_MEDIA_PAUSE, {}, "async_media_pause", [MediaPlayerEntityFeature.PAUSE]) component.async_register_entity_service(SERVICE_MEDIA_STOP, {}, "async_media_stop", [MediaPlayerEntityFeature.STOP]) component.async_register_entity_service( SERVICE_MEDIA_NEXT_TRACK, {}, "async_media_next_track", [MediaPlayerEntityFeature.NEXT_TRACK], ) component.async_register_entity_service( SERVICE_MEDIA_PREVIOUS_TRACK, {}, "async_media_previous_track", [MediaPlayerEntityFeature.PREVIOUS_TRACK], ) component.async_register_entity_service( SERVICE_CLEAR_PLAYLIST, {}, "async_clear_playlist", [MediaPlayerEntityFeature.CLEAR_PLAYLIST], ) component.async_register_entity_service( SERVICE_VOLUME_SET, vol.All( cv.make_entity_service_schema( {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float}), _rename_keys(volume=ATTR_MEDIA_VOLUME_LEVEL), ), "async_set_volume_level", [MediaPlayerEntityFeature.VOLUME_SET], ) component.async_register_entity_service( SERVICE_VOLUME_MUTE, vol.All( cv.make_entity_service_schema( {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean}), _rename_keys(mute=ATTR_MEDIA_VOLUME_MUTED), ), "async_mute_volume", [MediaPlayerEntityFeature.VOLUME_MUTE], ) component.async_register_entity_service( SERVICE_MEDIA_SEEK, vol.All( cv.make_entity_service_schema( {vol.Required(ATTR_MEDIA_SEEK_POSITION): cv.positive_float}), _rename_keys(position=ATTR_MEDIA_SEEK_POSITION), ), "async_media_seek", [MediaPlayerEntityFeature.SEEK], ) component.async_register_entity_service( SERVICE_JOIN, { vol.Required(ATTR_GROUP_MEMBERS): vol.All(cv.ensure_list, [cv.entity_id]) }, "async_join_players", [MediaPlayerEntityFeature.GROUPING], ) component.async_register_entity_service( SERVICE_SELECT_SOURCE, {vol.Required(ATTR_INPUT_SOURCE): cv.string}, "async_select_source", [MediaPlayerEntityFeature.SELECT_SOURCE], ) component.async_register_entity_service( SERVICE_SELECT_SOUND_MODE, {vol.Required(ATTR_SOUND_MODE): cv.string}, "async_select_sound_mode", [MediaPlayerEntityFeature.SELECT_SOUND_MODE], ) # Remove in Home Assistant 2022.9 def _rewrite_enqueue(value): """Rewrite the enqueue value.""" if ATTR_MEDIA_ENQUEUE not in value: pass elif value[ATTR_MEDIA_ENQUEUE] is True: value[ATTR_MEDIA_ENQUEUE] = MediaPlayerEnqueue.ADD _LOGGER.warning( "Playing media with enqueue set to True is deprecated. Use 'add' instead" ) elif value[ATTR_MEDIA_ENQUEUE] is False: value[ATTR_MEDIA_ENQUEUE] = MediaPlayerEnqueue.PLAY _LOGGER.warning( "Playing media with enqueue set to False is deprecated. Use 'play' instead" ) return value component.async_register_entity_service( SERVICE_PLAY_MEDIA, vol.All( cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA), _rewrite_enqueue, _rename_keys( media_type=ATTR_MEDIA_CONTENT_TYPE, media_id=ATTR_MEDIA_CONTENT_ID, enqueue=ATTR_MEDIA_ENQUEUE, ), ), "async_play_media", [MediaPlayerEntityFeature.PLAY_MEDIA], ) component.async_register_entity_service( SERVICE_SHUFFLE_SET, {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean}, "async_set_shuffle", [MediaPlayerEntityFeature.SHUFFLE_SET], ) component.async_register_entity_service( SERVICE_UNJOIN, {}, "async_unjoin_player", [MediaPlayerEntityFeature.GROUPING]) component.async_register_entity_service( SERVICE_REPEAT_SET, {vol.Required(ATTR_MEDIA_REPEAT): vol.In(REPEAT_MODES)}, "async_set_repeat", [MediaPlayerEntityFeature.REPEAT_SET], ) return True
def async_setup(hass, config): """Set up the weather component.""" component = EntityComponent(_LOGGER, DOMAIN, hass) yield from component.async_setup(config) return True
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()