async def async_setup_entry(opp, config_entry, async_add_entities): """Set up the Monoprice 6-zone amplifier platform.""" port = config_entry.data[CONF_PORT] monoprice = opp.data[DOMAIN][config_entry.entry_id][MONOPRICE_OBJECT] sources = _get_sources(config_entry) entities = [] for i in range(1, 4): for j in range(1, 7): zone_id = (i * 10) + j _LOGGER.info("Adding zone %d for port %s", zone_id, port) entities.append( MonopriceZone(monoprice, sources, config_entry.entry_id, zone_id)) # only call update before add if it's the first run so we can try to detect zones first_run = opp.data[DOMAIN][config_entry.entry_id][FIRST_RUN] async_add_entities(entities, first_run) platform = entity_platform.async_get_current_platform() def _call_service(entities, service_call): for entity in entities: if service_call.service == SERVICE_SNAPSHOT: entity.snapshot() elif service_call.service == SERVICE_RESTORE: entity.restore() @service.verify_domain_control(opp, DOMAIN) async def async_service_handle(service_call): """Handle for services.""" entities = await platform.async_extract_from_service(service_call) if not entities: return opp.async_add_executor_job(_call_service, entities, service_call) opp.services.async_register( DOMAIN, SERVICE_SNAPSHOT, async_service_handle, schema=cv.make_entity_service_schema({}), ) opp.services.async_register( DOMAIN, SERVICE_RESTORE, async_service_handle, schema=cv.make_entity_service_schema({}), )
async def async_setup(opp, config): """Set up the image processing.""" component = EntityComponent(_LOGGER, DOMAIN, opp, SCAN_INTERVAL) await component.async_setup(config) async def async_scan_service(service): """Service handler for scan.""" image_entities = await component.async_extract_from_service(service) update_tasks = [] for entity in image_entities: entity.async_set_context(service.context) update_tasks.append( asyncio.create_task(entity.async_update_op_state(True))) if update_tasks: await asyncio.wait(update_tasks) opp.services.async_register(DOMAIN, SERVICE_SCAN, async_scan_service, schema=make_entity_service_schema({})) return True
def setup(opp, config): """Set up the media extractor service.""" def play_media(call): """Get stream URL and send it to the play_media service.""" MediaExtractor(opp, config[DOMAIN], call.data).extract_and_send() opp.services.register( DOMAIN, SERVICE_PLAY_MEDIA, play_media, schema=cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA), ) return True
def async_register_entity_service(self, name, schema, func, required_features=None): """Register an entity service.""" if isinstance(schema, dict): schema = cv.make_entity_service_schema(schema) async def handle_service(call): """Handle the service.""" await self.opp.helpers.service.entity_service_call( self._platforms.values(), func, call, required_features) self.opp.services.async_register(self.domain, name, handle_service, schema)
def async_register_entity_service( self, name: str, schema: dict[str, Any] | vol.Schema, func: str | Callable[..., Any], required_features: list[int] | None = None, ) -> None: """Register an entity service.""" if isinstance(schema, dict): schema = cv.make_entity_service_schema(schema) async def handle_service(call: Callable) -> None: """Handle the service.""" await self.opp.helpers.service.entity_service_call( self._platforms.values(), func, call, required_features) self.opp.services.async_register(self.domain, name, handle_service, schema)
DISCOVERY_INTERVAL = 60 MESSAGE_TIMEOUT = 1.0 MESSAGE_RETRIES = 8 UNAVAILABLE_GRACE = 90 SERVICE_LIFX_SET_STATE = "set_state" ATTR_INFRARED = "infrared" ATTR_ZONES = "zones" ATTR_POWER = "power" LIFX_SET_STATE_SCHEMA = cv.make_entity_service_schema({ **LIGHT_TURN_ON_SCHEMA, ATTR_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)), ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]), ATTR_POWER: cv.boolean, }) SERVICE_EFFECT_PULSE = "effect_pulse" SERVICE_EFFECT_COLORLOOP = "effect_colorloop" SERVICE_EFFECT_STOP = "effect_stop" ATTR_POWER_ON = "power_on" ATTR_PERIOD = "period" ATTR_CYCLES = "cycles" ATTR_SPREAD = "spread" ATTR_CHANGE = "change"
def async_setup_services(opp: OpenPeerPower): # noqa: C901 """Create and register services for the ISY integration.""" existing_services = opp.services.async_services().get(DOMAIN) if existing_services and any(service in INTEGRATION_SERVICES for service in existing_services): # Integration-level services have already been added. Return. return async def async_system_query_service_handler(service): """Handle a system query service call.""" address = service.data.get(CONF_ADDRESS) isy_name = service.data.get(CONF_ISY) for config_entry_id in opp.data[DOMAIN]: isy = opp.data[DOMAIN][config_entry_id][ISY994_ISY] if isy_name and isy_name != isy.configuration["name"]: continue # If an address is provided, make sure we query the correct ISY. # Otherwise, query the whole system on all ISY's connected. if address and isy.nodes.get_by_id(address) is not None: _LOGGER.debug( "Requesting query of device %s on ISY %s", address, isy.configuration["uuid"], ) await isy.query(address) return _LOGGER.debug("Requesting system query of ISY %s", isy.configuration["uuid"]) await isy.query() async def async_run_network_resource_service_handler(service): """Handle a network resource service call.""" address = service.data.get(CONF_ADDRESS) name = service.data.get(CONF_NAME) isy_name = service.data.get(CONF_ISY) for config_entry_id in opp.data[DOMAIN]: isy = opp.data[DOMAIN][config_entry_id][ISY994_ISY] if isy_name and isy_name != isy.configuration["name"]: continue if not hasattr(isy, "networking") or isy.networking is None: continue command = None if address: command = isy.networking.get_by_id(address) if name: command = isy.networking.get_by_name(name) if command is not None: await command.run() return _LOGGER.error( "Could not run network resource command; not found or enabled on the ISY" ) async def async_send_program_command_service_handler(service): """Handle a send program command service call.""" address = service.data.get(CONF_ADDRESS) name = service.data.get(CONF_NAME) command = service.data.get(CONF_COMMAND) isy_name = service.data.get(CONF_ISY) for config_entry_id in opp.data[DOMAIN]: isy = opp.data[DOMAIN][config_entry_id][ISY994_ISY] if isy_name and isy_name != isy.configuration["name"]: continue program = None if address: program = isy.programs.get_by_id(address) if name: program = isy.programs.get_by_name(name) if program is not None: await getattr(program, command)() return _LOGGER.error( "Could not send program command; not found or enabled on the ISY") async def async_set_variable_service_handler(service): """Handle a set variable service call.""" address = service.data.get(CONF_ADDRESS) vtype = service.data.get(CONF_TYPE) name = service.data.get(CONF_NAME) value = service.data.get(CONF_VALUE) init = service.data.get(CONF_INIT, False) isy_name = service.data.get(CONF_ISY) for config_entry_id in opp.data[DOMAIN]: isy = opp.data[DOMAIN][config_entry_id][ISY994_ISY] if isy_name and isy_name != isy.configuration["name"]: continue variable = None if name: variable = isy.variables.get_by_name(name) if address and vtype: variable = isy.variables.vobjs[vtype].get(address) if variable is not None: await variable.set_value(value, init) return _LOGGER.error( "Could not set variable value; not found or enabled on the ISY") async def async_cleanup_registry_entries(service) -> None: """Remove extra entities that are no longer part of the integration.""" entity_registry = await er.async_get_registry(opp) config_ids = [] current_unique_ids = [] for config_entry_id in opp.data[DOMAIN]: entries_for_this_config = er.async_entries_for_config_entry( entity_registry, config_entry_id) config_ids.extend([(entity.unique_id, entity.entity_id) for entity in entries_for_this_config]) opp_isy_data = opp.data[DOMAIN][config_entry_id] uuid = opp_isy_data[ISY994_ISY].configuration["uuid"] for platform in PLATFORMS: for node in opp_isy_data[ISY994_NODES][platform]: if hasattr(node, "address"): current_unique_ids.append(f"{uuid}_{node.address}") for platform in PROGRAM_PLATFORMS: for _, node, _ in opp_isy_data[ISY994_PROGRAMS][platform]: if hasattr(node, "address"): current_unique_ids.append(f"{uuid}_{node.address}") for node in opp_isy_data[ISY994_VARIABLES]: if hasattr(node, "address"): current_unique_ids.append(f"{uuid}_{node.address}") extra_entities = [ entity_id for unique_id, entity_id in config_ids if unique_id not in current_unique_ids ] for entity_id in extra_entities: if entity_registry.async_is_registered(entity_id): entity_registry.async_remove(entity_id) _LOGGER.debug( "Cleaning up ISY994 Entities and devices: Config Entries: %s, Current Entries: %s, " "Extra Entries Removed: %s", len(config_ids), len(current_unique_ids), len(extra_entities), ) async def async_reload_config_entries(service) -> None: """Trigger a reload of all ISY994 config entries.""" for config_entry_id in opp.data[DOMAIN]: opp.async_create_task( opp.config_entries.async_reload(config_entry_id)) opp.services.async_register( domain=DOMAIN, service=SERVICE_SYSTEM_QUERY, service_func=async_system_query_service_handler, schema=SERVICE_SYSTEM_QUERY_SCHEMA, ) opp.services.async_register( domain=DOMAIN, service=SERVICE_RUN_NETWORK_RESOURCE, service_func=async_run_network_resource_service_handler, schema=SERVICE_RUN_NETWORK_RESOURCE_SCHEMA, ) opp.services.async_register( domain=DOMAIN, service=SERVICE_SEND_PROGRAM_COMMAND, service_func=async_send_program_command_service_handler, schema=SERVICE_SEND_PROGRAM_COMMAND_SCHEMA, ) opp.services.async_register( domain=DOMAIN, service=SERVICE_SET_VARIABLE, service_func=async_set_variable_service_handler, schema=SERVICE_SET_VARIABLE_SCHEMA, ) opp.services.async_register( domain=DOMAIN, service=SERVICE_CLEANUP, service_func=async_cleanup_registry_entries, ) opp.services.async_register(domain=DOMAIN, service=SERVICE_RELOAD, service_func=async_reload_config_entries) async def _async_send_raw_node_command(call: ServiceCall): await opp.helpers.service.entity_service_call( async_get_platforms(opp, DOMAIN), "async_send_raw_node_command", call) opp.services.async_register( domain=DOMAIN, service=SERVICE_SEND_RAW_NODE_COMMAND, schema=cv.make_entity_service_schema( SERVICE_SEND_RAW_NODE_COMMAND_SCHEMA), service_func=_async_send_raw_node_command, ) async def _async_send_node_command(call: ServiceCall): await opp.helpers.service.entity_service_call( async_get_platforms(opp, DOMAIN), "async_send_node_command", call) opp.services.async_register( domain=DOMAIN, service=SERVICE_SEND_NODE_COMMAND, schema=cv.make_entity_service_schema(SERVICE_SEND_NODE_COMMAND_SCHEMA), service_func=_async_send_node_command, ) async def _async_get_zwave_parameter(call: ServiceCall): await opp.helpers.service.entity_service_call( async_get_platforms(opp, DOMAIN), "async_get_zwave_parameter", call) opp.services.async_register( domain=DOMAIN, service=SERVICE_GET_ZWAVE_PARAMETER, schema=cv.make_entity_service_schema( SERVICE_GET_ZWAVE_PARAMETER_SCHEMA), service_func=_async_get_zwave_parameter, ) async def _async_set_zwave_parameter(call: ServiceCall): await opp.helpers.service.entity_service_call( async_get_platforms(opp, DOMAIN), "async_set_zwave_parameter", call) opp.services.async_register( domain=DOMAIN, service=SERVICE_SET_ZWAVE_PARAMETER, schema=cv.make_entity_service_schema( SERVICE_SET_ZWAVE_PARAMETER_SCHEMA), service_func=_async_set_zwave_parameter, ) async def _async_rename_node(call: ServiceCall): await opp.helpers.service.entity_service_call( async_get_platforms(opp, DOMAIN), "async_rename_node", call) opp.services.async_register( domain=DOMAIN, service=SERVICE_RENAME_NODE, schema=cv.make_entity_service_schema(SERVICE_RENAME_NODE_SCHEMA), service_func=_async_rename_node, )
SCAN_INTERVAL = timedelta(seconds=60) CONVERTIBLE_ATTRIBUTE = [ ATTR_TEMPERATURE, ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH ] _LOGGER = logging.getLogger(__name__) SET_TEMPERATURE_SCHEMA = vol.All( cv.has_at_least_one_key(ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW), make_entity_service_schema({ vol.Exclusive(ATTR_TEMPERATURE, "temperature"): vol.Coerce(float), vol.Inclusive(ATTR_TARGET_TEMP_HIGH, "temperature"): vol.Coerce(float), vol.Inclusive(ATTR_TARGET_TEMP_LOW, "temperature"): vol.Coerce(float), vol.Optional(ATTR_HVAC_MODE): vol.In(HVAC_MODES), }), ) async def async_setup(opp: OpenPeerPower, config: ConfigType) -> bool: """Set up climate entities.""" component = opp.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, opp, SCAN_INTERVAL) await component.async_setup(config) component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on")
async def async_setup(opp, config): """Track states and offer events for media_players.""" component = opp.data[DOMAIN] = EntityComponent(logging.getLogger(__name__), DOMAIN, opp, SCAN_INTERVAL) opp.components.websocket_api.async_register_command( websocket_handle_thumbnail) opp.components.websocket_api.async_register_command(websocket_browse_media) opp.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_JOIN, { vol.Required(ATTR_GROUP_MEMBERS): vol.All(cv.ensure_list, [cv.entity_id]) }, "async_join_players", [SUPPORT_GROUPING], ) 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_UNJOIN, {}, "async_unjoin_player", [SUPPORT_GROUPING]) 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(opp, config): """Expose light control via state machine and services.""" component = opp.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, opp, SCAN_INTERVAL) await component.async_setup(config) # load profiles from files profiles_valid = await Profiles.load_profiles(opp) if not profiles_valid: return False def preprocess_data(data): """Preprocess the service data.""" base = {} for entity_field in cv.ENTITY_SERVICE_FIELDS: if entity_field in data: base[entity_field] = data.pop(entity_field) preprocess_turn_on_alternatives(data) turn_lights_off, off_params = preprocess_turn_off(data) base["params"] = data base["turn_lights_off"] = turn_lights_off base["off_params"] = off_params 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 = call.data["params"] turn_light_off = call.data["turn_lights_off"] off_params = call.data["off_params"] if not params: default_profile = Profiles.get_default(light.entity_id) if default_profile is not None: params = {ATTR_PROFILE: default_profile} preprocess_turn_on_alternatives(params) turn_light_off, off_params = preprocess_turn_off(params) elif ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params: brightness = light.brightness if light.is_on else 0 params = params.copy() if ATTR_BRIGHTNESS_STEP in params: brightness += params.pop(ATTR_BRIGHTNESS_STEP) else: brightness += int( params.pop(ATTR_BRIGHTNESS_STEP_PCT) / 100 * 255) params[ATTR_BRIGHTNESS] = max(0, min(255, brightness)) turn_light_off, off_params = preprocess_turn_off(params) if turn_light_off: await light.async_turn_off(**off_params) else: await light.async_turn_on(**params) # Listen for light on and light off service calls. component.async_register_entity_service( SERVICE_TURN_ON, vol.All(cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA), preprocess_data), async_handle_light_on_service, ) component.async_register_entity_service( SERVICE_TURN_OFF, { ATTR_TRANSITION: VALID_TRANSITION, ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]), }, "async_turn_off", ) component.async_register_entity_service(SERVICE_TOGGLE, LIGHT_TURN_ON_SCHEMA, "async_toggle") return True
_LOGGER = logging.getLogger(__name__) # the desired duration, in hours, of the cycle ATTR_DURATION = "duration" ATTR_CYCLE_LAST_UPDATED = "cycle_last_updated" ATTR_MODE = "mode" # the hour of the day at which to start the cycle (0-23) ATTR_START_HOUR = "start_hour" SET_PRIMARY_FILTRATION_SCHEMA = vol.All( cv.has_at_least_one_key(ATTR_DURATION, ATTR_START_HOUR), cv.make_entity_service_schema( { vol.Optional(ATTR_DURATION): vol.All(int, vol.Range(min=1, max=24)), vol.Optional(ATTR_START_HOUR): vol.All(int, vol.Range(min=0, max=23)), }, ), ) SET_SECONDARY_FILTRATION_SCHEMA = { vol.Required(ATTR_MODE): vol.In({ mode.name.lower() for mode in smarttub.SpaSecondaryFiltrationCycle.SecondaryFiltrationMode }), }
profiles.apply_default(light.entity_id, True, params) await light.async_turn_off(**filter_turn_off_params(light, params)) async def async_handle_toggle_service(light, call): """Handle toggling a light.""" if light.is_on: await async_handle_light_off_service(light, call) else: await async_handle_light_on_service(light, call) # Listen for light on and light off service calls. component.async_register_entity_service( SERVICE_TURN_ON, vol.All(cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA), preprocess_data), async_handle_light_on_service, ) component.async_register_entity_service( SERVICE_TURN_OFF, vol.All(cv.make_entity_service_schema(LIGHT_TURN_OFF_SCHEMA), preprocess_data), async_handle_light_off_service, ) component.async_register_entity_service( SERVICE_TOGGLE, vol.All(cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA), preprocess_data),
vol.Optional(CONF_DESCRIPTION, default=""): cv.string, vol.Optional(CONF_FIELDS, default={}): { cv.string: { vol.Optional(CONF_DESCRIPTION): cv.string, vol.Optional(CONF_EXAMPLE): cv.string, } }, }) CONFIG_SCHEMA = vol.Schema( {DOMAIN: cv.schema_with_slug_keys(SCRIPT_ENTRY_SCHEMA)}, extra=vol.ALLOW_EXTRA) SCRIPT_SERVICE_SCHEMA = vol.Schema(dict) SCRIPT_TURN_ONOFF_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_VARIABLES): dict}) RELOAD_SERVICE_SCHEMA = vol.Schema({}) @bind_opp def is_on(opp, entity_id): """Return if the script is on based on the statemachine.""" return opp.states.is_state(entity_id, STATE_ON) @callback def scripts_with_entity(opp: OpenPeerPower, entity_id: str) -> List[str]: """Return all scripts that reference the entity.""" if DOMAIN not in opp.data: return []
async def async_setup_entry( opp: OpenPeerPower, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up Sonos from a config entry.""" platform = entity_platform.async_get_current_platform() @callback def async_create_entities(speaker: SonosSpeaker) -> None: """Handle device discovery and create entities.""" async_add_entities([SonosMediaPlayerEntity(speaker)]) @service.verify_domain_control(opp, SONOS_DOMAIN) async def async_service_handle(service_call: ServiceCall) -> None: """Handle dispatched services.""" assert platform is not None entities = await platform.async_extract_from_service(service_call) if not entities: return speakers = [] for entity in entities: assert isinstance(entity, SonosMediaPlayerEntity) speakers.append(entity.speaker) if service_call.service == SERVICE_JOIN: master = platform.entities.get(service_call.data[ATTR_MASTER]) if master: await SonosSpeaker.join_multi(opp, master.speaker, speakers ) # type: ignore[arg-type] else: _LOGGER.error( "Invalid master specified for join service: %s", service_call.data[ATTR_MASTER], ) elif service_call.service == SERVICE_UNJOIN: await SonosSpeaker.unjoin_multi(opp, speakers) # type: ignore[arg-type] elif service_call.service == SERVICE_SNAPSHOT: await SonosSpeaker.snapshot_multi( opp, speakers, service_call.data[ATTR_WITH_GROUP] # type: ignore[arg-type] ) elif service_call.service == SERVICE_RESTORE: await SonosSpeaker.restore_multi( opp, speakers, service_call.data[ATTR_WITH_GROUP] # type: ignore[arg-type] ) config_entry.async_on_unload( async_dispatcher_connect(opp, SONOS_CREATE_MEDIA_PLAYER, async_create_entities)) opp.services.async_register( SONOS_DOMAIN, SERVICE_JOIN, async_service_handle, cv.make_entity_service_schema( {vol.Required(ATTR_MASTER): cv.entity_id}), ) opp.services.async_register( SONOS_DOMAIN, SERVICE_UNJOIN, async_service_handle, cv.make_entity_service_schema({}), ) join_unjoin_schema = cv.make_entity_service_schema( {vol.Optional(ATTR_WITH_GROUP, default=True): cv.boolean}) opp.services.async_register(SONOS_DOMAIN, SERVICE_SNAPSHOT, async_service_handle, join_unjoin_schema) opp.services.async_register(SONOS_DOMAIN, SERVICE_RESTORE, async_service_handle, join_unjoin_schema) platform.async_register_entity_service( # type: ignore SERVICE_SET_TIMER, { vol.Required(ATTR_SLEEP_TIME): vol.All( vol.Coerce(int), vol.Range(min=0, max=86399) ) }, "set_sleep_timer", ) platform.async_register_entity_service(SERVICE_CLEAR_TIMER, {}, "clear_sleep_timer") # type: ignore platform.async_register_entity_service( # type: ignore SERVICE_UPDATE_ALARM, { vol.Required(ATTR_ALARM_ID): cv.positive_int, vol.Optional(ATTR_TIME): cv.time, vol.Optional(ATTR_VOLUME): cv.small_float, vol.Optional(ATTR_ENABLED): cv.boolean, vol.Optional(ATTR_INCLUDE_LINKED_ZONES): cv.boolean, }, "set_alarm", ) platform.async_register_entity_service( # type: ignore SERVICE_SET_OPTION, { vol.Optional(ATTR_BUTTONS_ENABLED): cv.boolean, vol.Optional(ATTR_NIGHT_SOUND): cv.boolean, vol.Optional(ATTR_SPEECH_ENHANCE): cv.boolean, vol.Optional(ATTR_STATUS_LIGHT): cv.boolean, }, "set_option", ) platform.async_register_entity_service( # type: ignore SERVICE_PLAY_QUEUE, {vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int}, "play_queue", ) platform.async_register_entity_service( # type: ignore SERVICE_REMOVE_FROM_QUEUE, {vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int}, "remove_from_queue", )
async def async_setup(opp, config): """Set up all groups found defined in the configuration.""" component = opp.data.get(DOMAIN) if component is None: component = opp.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, opp) await _async_process_config(opp, 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(opp, conf, component) await component.async_add_entities(auto) opp.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 = 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( opp, 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_op_state() return # remove group if service.service == SERVICE_REMOVE: await component.async_remove_entity(entity_id) opp.services.async_register( DOMAIN, SERVICE_SET, locked_service_handler, schema=vol.All( cv.deprecated(ATTR_CONTROL, invalidation_version="0.107.0"), cv.deprecated(ATTR_VIEW, invalidation_version="0.107.0"), cv.deprecated(ATTR_VISIBLE, invalidation_version="0.107.0"), vol.Schema({ vol.Required(ATTR_OBJECT_ID): cv.slug, vol.Optional(ATTR_NAME): cv.string, vol.Optional(ATTR_VIEW): cv.boolean, vol.Optional(ATTR_ICON): cv.string, vol.Optional(ATTR_CONTROL): CONTROL_TYPES, vol.Optional(ATTR_VISIBLE): cv.boolean, vol.Optional(ATTR_ALL): cv.boolean, vol.Exclusive(ATTR_ENTITIES, "entities"): cv.entity_ids, vol.Exclusive(ATTR_ADD_ENTITIES, "entities"): cv.entity_ids, }), ), ) opp.services.async_register( DOMAIN, SERVICE_REMOVE, groups_service_handler, schema=vol.Schema({vol.Required(ATTR_OBJECT_ID): cv.slug}), ) async def visibility_service_handler(service): """Change visibility of a group.""" visible = service.data.get(ATTR_VISIBLE) _LOGGER.warning( "The group.set_visibility service has been deprecated and will" "be removed in Open Peer Power 0.107.0.") tasks = [] for group in await component.async_extract_from_service( service, expand_group=False): group.visible = visible tasks.append(group.async_update_op_state()) if tasks: await asyncio.wait(tasks) opp.services.async_register( DOMAIN, SERVICE_SET_VISIBILITY, visibility_service_handler, schema=make_entity_service_schema( {vol.Required(ATTR_VISIBLE): cv.boolean}), ) return True
vol.Inclusive(CONF_CLIENT_ID, CONF_OAUTH, msg=CONF_MISSING_OAUTH_MSG): cv.string, vol.Inclusive(CONF_CLIENT_SECRET, CONF_OAUTH, msg=CONF_MISSING_OAUTH_MSG): cv.string, vol.Optional(CONF_LOCAL_CONTROL, default=False): cv.boolean, }) }, extra=vol.ALLOW_EXTRA, ) RENAME_DEVICE_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_NAME): cv.string}, extra=vol.ALLOW_EXTRA) DELETE_DEVICE_SCHEMA = make_entity_service_schema({}, extra=vol.ALLOW_EXTRA) SET_PAIRING_MODE_SCHEMA = vol.Schema( { vol.Required(ATTR_HUB_NAME): cv.string, vol.Required(ATTR_PAIRING_MODE): cv.string, vol.Optional(ATTR_KIDDE_RADIO_CODE): cv.string, }, extra=vol.ALLOW_EXTRA, ) SET_VOLUME_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_VOLUME): vol.In(VOLUMES)})
DOMAIN = "upb" ATTR_ADDRESS = "address" ATTR_BLINK_RATE = "blink_rate" ATTR_BRIGHTNESS = "brightness" ATTR_BRIGHTNESS_PCT = "brightness_pct" ATTR_RATE = "rate" CONF_NETWORK = "network" EVENT_UPB_SCENE_CHANGED = "upb.scene_changed" VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)) VALID_BRIGHTNESS_PCT = vol.All(vol.Coerce(float), vol.Range(min=0, max=100)) VALID_RATE = vol.All(vol.Coerce(float), vol.Clamp(min=-1, max=3600)) UPB_BRIGHTNESS_RATE_SCHEMA = vol.All( cv.has_at_least_one_key(ATTR_BRIGHTNESS, ATTR_BRIGHTNESS_PCT), cv.make_entity_service_schema( { vol.Exclusive(ATTR_BRIGHTNESS, ATTR_BRIGHTNESS): VALID_BRIGHTNESS, vol.Exclusive(ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS): VALID_BRIGHTNESS_PCT, vol.Optional(ATTR_RATE, default=-1): VALID_RATE, } ), ) UPB_BLINK_RATE_SCHEMA = { vol.Required(ATTR_BLINK_RATE, default=0.5): vol.All( vol.Coerce(float), vol.Range(min=0, max=4.25) ) }
ATTR_MEDIA_TYPE = "media_type" ATTR_MEDIA_NAME = "media_name" ATTR_MEDIA_ARTIST_NAME = "artist_name" ATTR_MEDIA_ID = "media_id" ATTR_METHOD = "method" KODI_ADD_MEDIA_SCHEMA = { vol.Required(ATTR_MEDIA_TYPE): cv.string, vol.Optional(ATTR_MEDIA_ID): cv.string, vol.Optional(ATTR_MEDIA_NAME): cv.string, vol.Optional(ATTR_MEDIA_ARTIST_NAME): cv.string, } KODI_CALL_METHOD_SCHEMA = cv.make_entity_service_schema( {vol.Required(ATTR_METHOD): cv.string}, extra=vol.ALLOW_EXTRA ) def find_matching_config_entries_for_host(opp, host): """Search existing config entries for one matching the host.""" for entry in opp.config_entries.async_entries(DOMAIN): if entry.data[CONF_HOST] == host: return entry return None async def async_setup_platform(opp, config, async_add_entities, discovery_info=None): """Set up the Kodi platform.""" if discovery_info: # Now handled by zeroconf in the config flow
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) SERVICE_SEND_COMMAND = "send_command" SERVICE_LEARN_COMMAND = "learn_command" SERVICE_DELETE_COMMAND = "delete_command" SERVICE_SYNC = "sync" DEFAULT_NUM_REPEATS = 1 DEFAULT_DELAY_SECS = 0.4 DEFAULT_HOLD_SECS = 0 SUPPORT_LEARN_COMMAND = 1 SUPPORT_DELETE_COMMAND = 2 SUPPORT_ACTIVITY = 4 REMOTE_SERVICE_ACTIVITY_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_ACTIVITY): cv.string}) @bind_opp def is_on(opp: OpenPeerPower, entity_id: str) -> bool: """Return if the remote is on based on the statemachine.""" return opp.states.is_state(entity_id, STATE_ON) async def async_setup(opp: OpenPeerPower, config: ConfigType) -> bool: """Track states and offer events for remotes.""" component = opp.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, opp, SCAN_INTERVAL) await component.async_setup(config) component.async_register_entity_service(SERVICE_TURN_OFF,
from openpeerpower.helpers.entity_component import EntityComponent # mypy: allow-untyped-defs, no-check-untyped-defs _LOGGER = logging.getLogger(__name__) ATTR_CHANGED_BY = "changed_by" DOMAIN = "lock" SCAN_INTERVAL = timedelta(seconds=30) ENTITY_ID_FORMAT = DOMAIN + ".{}" MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) LOCK_SERVICE_SCHEMA = make_entity_service_schema({vol.Optional(ATTR_CODE): cv.string}) # Bitfield of features supported by the lock entity SUPPORT_OPEN = 1 PROP_TO_ATTR = {"changed_by": ATTR_CHANGED_BY, "code_format": ATTR_CODE_FORMAT} async def async_setup(opp, config): """Track states and offer events for locks.""" component = opp.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, opp, SCAN_INTERVAL) await component.async_setup(config) component.async_register_entity_service( SERVICE_UNLOCK, LOCK_SERVICE_SCHEMA, "async_unlock"
ATTR_LAST_ACTION, ATTR_LAST_TRIGGERED, ATTR_VARIABLES, CONF_FIELDS, CONF_TRACE, DOMAIN, ENTITY_ID_FORMAT, EVENT_SCRIPT_STARTED, LOGGER, ) from .helpers import async_get_blueprints from .trace import trace_script SCRIPT_SERVICE_SCHEMA = vol.Schema(dict) SCRIPT_TURN_ONOFF_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_VARIABLES): { str: cv.match_all }}) RELOAD_SERVICE_SCHEMA = vol.Schema({}) @bind_opp def is_on(opp, entity_id): """Return if the script is on based on the statemachine.""" return opp.states.is_state(entity_id, STATE_ON) @callback def scripts_with_entity(opp: OpenPeerPower, entity_id: str) -> list[str]: """Return all scripts that reference the entity.""" if DOMAIN not in opp.data: return []