Entity service (#15991)

* Add entity service helper

* Use entity service helper

* Context
This commit is contained in:
Paulus Schoutsen 2018-08-16 09:50:11 +02:00 committed by GitHub
parent e52ba87af1
commit b682e48e12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 276 additions and 387 deletions

View file

@ -26,20 +26,6 @@ ATTR_CHANGED_BY = 'changed_by'
ENTITY_ID_FORMAT = DOMAIN + '.{}'
SERVICE_TO_METHOD = {
SERVICE_ALARM_DISARM: 'alarm_disarm',
SERVICE_ALARM_ARM_HOME: 'alarm_arm_home',
SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away',
SERVICE_ALARM_ARM_NIGHT: 'alarm_arm_night',
SERVICE_ALARM_ARM_CUSTOM_BYPASS: 'alarm_arm_custom_bypass',
SERVICE_ALARM_TRIGGER: 'alarm_trigger'
}
ATTR_TO_PROPERTY = [
ATTR_CODE,
ATTR_CODE_FORMAT
]
ALARM_SERVICE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Optional(ATTR_CODE): cv.string,
@ -126,30 +112,30 @@ def async_setup(hass, config):
yield from component.async_setup(config)
@asyncio.coroutine
def async_alarm_service_handler(service):
"""Map services to methods on Alarm."""
target_alarms = component.async_extract_from_service(service)
code = service.data.get(ATTR_CODE)
method = "async_{}".format(SERVICE_TO_METHOD[service.service])
update_tasks = []
for alarm in target_alarms:
yield from getattr(alarm, method)(code)
if not alarm.should_poll:
continue
update_tasks.append(alarm.async_update_ha_state(True))
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
for service in SERVICE_TO_METHOD:
hass.services.async_register(
DOMAIN, service, async_alarm_service_handler,
schema=ALARM_SERVICE_SCHEMA)
component.async_register_entity_service(
SERVICE_ALARM_DISARM, ALARM_SERVICE_SCHEMA,
'async_alarm_disarm'
)
component.async_register_entity_service(
SERVICE_ALARM_ARM_HOME, ALARM_SERVICE_SCHEMA,
'async_alarm_arm_home'
)
component.async_register_entity_service(
SERVICE_ALARM_ARM_AWAY, ALARM_SERVICE_SCHEMA,
'async_alarm_arm_away'
)
component.async_register_entity_service(
SERVICE_ALARM_ARM_NIGHT, ALARM_SERVICE_SCHEMA,
'async_alarm_arm_night'
)
component.async_register_entity_service(
SERVICE_ALARM_ARM_CUSTOM_BYPASS, ALARM_SERVICE_SCHEMA,
'async_alarm_arm_custom_bypass'
)
component.async_register_entity_service(
SERVICE_ALARM_TRIGGER, ALARM_SERVICE_SCHEMA,
'async_alarm_trigger'
)
return True

View file

@ -4,7 +4,6 @@ Component to count within automations.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/counter/
"""
import asyncio
import logging
import voluptuous as vol
@ -114,27 +113,15 @@ async def async_setup(hass, config):
if not entities:
return False
async def async_handler_service(service):
"""Handle a call to the counter services."""
target_counters = component.async_extract_from_service(service)
if service.service == SERVICE_INCREMENT:
attr = 'async_increment'
elif service.service == SERVICE_DECREMENT:
attr = 'async_decrement'
elif service.service == SERVICE_RESET:
attr = 'async_reset'
tasks = [getattr(counter, attr)() for counter in target_counters]
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_INCREMENT, async_handler_service)
hass.services.async_register(
DOMAIN, SERVICE_DECREMENT, async_handler_service)
hass.services.async_register(
DOMAIN, SERVICE_RESET, async_handler_service)
component.async_register_entity_service(
SERVICE_INCREMENT, SERVICE_SCHEMA,
'async_increment')
component.async_register_entity_service(
SERVICE_DECREMENT, SERVICE_SCHEMA,
'async_decrement')
component.async_register_entity_service(
SERVICE_RESET, SERVICE_SCHEMA,
'async_reset')
await component.async_add_entities(entities)
return True

View file

@ -4,7 +4,6 @@ Support for Cover devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/cover/
"""
import asyncio
from datetime import timedelta
import functools as ft
import logging
@ -73,21 +72,6 @@ COVER_SET_COVER_TILT_POSITION_SCHEMA = COVER_SERVICE_SCHEMA.extend({
vol.All(vol.Coerce(int), vol.Range(min=0, max=100)),
})
SERVICE_TO_METHOD = {
SERVICE_OPEN_COVER: {'method': 'async_open_cover'},
SERVICE_CLOSE_COVER: {'method': 'async_close_cover'},
SERVICE_SET_COVER_POSITION: {
'method': 'async_set_cover_position',
'schema': COVER_SET_COVER_POSITION_SCHEMA},
SERVICE_STOP_COVER: {'method': 'async_stop_cover'},
SERVICE_OPEN_COVER_TILT: {'method': 'async_open_cover_tilt'},
SERVICE_CLOSE_COVER_TILT: {'method': 'async_close_cover_tilt'},
SERVICE_STOP_COVER_TILT: {'method': 'async_stop_cover_tilt'},
SERVICE_SET_COVER_TILT_POSITION: {
'method': 'async_set_cover_tilt_position',
'schema': COVER_SET_COVER_TILT_POSITION_SCHEMA},
}
@bind_hass
def is_closed(hass, entity_id=None):
@ -161,30 +145,46 @@ async def async_setup(hass, config):
await component.async_setup(config)
async def async_handle_cover_service(service):
"""Handle calls to the cover services."""
covers = component.async_extract_from_service(service)
method = SERVICE_TO_METHOD.get(service.service)
params = service.data.copy()
params.pop(ATTR_ENTITY_ID, None)
component.async_register_entity_service(
SERVICE_OPEN_COVER, COVER_SERVICE_SCHEMA,
'async_open_cover'
)
# call method
update_tasks = []
for cover in covers:
await getattr(cover, method['method'])(**params)
if not cover.should_poll:
continue
update_tasks.append(cover.async_update_ha_state(True))
component.async_register_entity_service(
SERVICE_CLOSE_COVER, COVER_SERVICE_SCHEMA,
'async_close_cover'
)
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
component.async_register_entity_service(
SERVICE_SET_COVER_POSITION, COVER_SET_COVER_POSITION_SCHEMA,
'async_set_cover_position'
)
component.async_register_entity_service(
SERVICE_STOP_COVER, COVER_SERVICE_SCHEMA,
'async_stop_cover'
)
component.async_register_entity_service(
SERVICE_OPEN_COVER_TILT, COVER_SERVICE_SCHEMA,
'async_open_cover_tilt'
)
component.async_register_entity_service(
SERVICE_CLOSE_COVER_TILT, COVER_SERVICE_SCHEMA,
'async_close_cover_tilt'
)
component.async_register_entity_service(
SERVICE_STOP_COVER_TILT, COVER_SERVICE_SCHEMA,
'async_stop_cover_tilt'
)
component.async_register_entity_service(
SERVICE_SET_COVER_TILT_POSITION, COVER_SET_COVER_TILT_POSITION_SCHEMA,
'async_set_cover_tilt_position'
)
for service_name in SERVICE_TO_METHOD:
schema = SERVICE_TO_METHOD[service_name].get(
'schema', COVER_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, service_name, async_handle_cover_service,
schema=schema)
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
INTENT_OPEN_COVER, DOMAIN, SERVICE_OPEN_COVER,
"Opened {}"))

View file

@ -4,7 +4,6 @@ Component to keep track of user controlled booleans for within automation.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/input_boolean/
"""
import asyncio
import logging
import voluptuous as vol
@ -84,30 +83,20 @@ async def async_setup(hass, config):
if not entities:
return False
async def async_handler_service(service):
"""Handle a calls to the input boolean services."""
target_inputs = component.async_extract_from_service(service)
component.async_register_entity_service(
SERVICE_TURN_ON, SERVICE_SCHEMA,
'async_turn_on'
)
if service.service == SERVICE_TURN_ON:
attr = 'async_turn_on'
elif service.service == SERVICE_TURN_OFF:
attr = 'async_turn_off'
else:
attr = 'async_toggle'
component.async_register_entity_service(
SERVICE_TURN_OFF, SERVICE_SCHEMA,
'async_turn_off'
)
tasks = [getattr(input_b, attr)() for input_b in target_inputs]
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_handler_service,
schema=SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_handler_service,
schema=SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TOGGLE, async_handler_service,
schema=SERVICE_SCHEMA)
component.async_register_entity_service(
SERVICE_TOGGLE, SERVICE_SCHEMA,
'async_toggle'
)
await component.async_add_entities(entities)
return True

View file

@ -82,19 +82,6 @@ CONFIG_SCHEMA = vol.Schema({
}, required=True, extra=vol.ALLOW_EXTRA)
SERVICE_TO_METHOD = {
SERVICE_SET_VALUE: {
'method': 'async_set_value',
'schema': SERVICE_SET_VALUE_SCHEMA},
SERVICE_INCREMENT: {
'method': 'async_increment',
'schema': SERVICE_DEFAULT_SCHEMA},
SERVICE_DECREMENT: {
'method': 'async_decrement',
'schema': SERVICE_DEFAULT_SCHEMA},
}
@bind_hass
def set_value(hass, entity_id, value):
"""Set input_number to value."""
@ -144,28 +131,20 @@ def async_setup(hass, config):
if not entities:
return False
@asyncio.coroutine
def async_handle_service(service):
"""Handle calls to input_number services."""
target_inputs = component.async_extract_from_service(service)
method = SERVICE_TO_METHOD.get(service.service)
params = service.data.copy()
params.pop(ATTR_ENTITY_ID, None)
component.async_register_entity_service(
SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA,
'async_set_value'
)
# call method
update_tasks = []
for target_input in target_inputs:
yield from getattr(target_input, method['method'])(**params)
if not target_input.should_poll:
continue
update_tasks.append(target_input.async_update_ha_state(True))
component.async_register_entity_service(
SERVICE_INCREMENT, SERVICE_DEFAULT_SCHEMA,
'async_increment'
)
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
for service, data in SERVICE_TO_METHOD.items():
hass.services.async_register(
DOMAIN, service, async_handle_service, schema=data['schema'])
component.async_register_entity_service(
SERVICE_DECREMENT, SERVICE_DEFAULT_SCHEMA,
'async_decrement'
)
yield from component.async_add_entities(entities)
return True

View file

@ -129,61 +129,25 @@ def async_setup(hass, config):
if not entities:
return False
@asyncio.coroutine
def async_select_option_service(call):
"""Handle a calls to the input select option service."""
target_inputs = component.async_extract_from_service(call)
component.async_register_entity_service(
SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION_SCHEMA,
'async_select_option'
)
tasks = [input_select.async_select_option(call.data[ATTR_OPTION])
for input_select in target_inputs]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
component.async_register_entity_service(
SERVICE_SELECT_NEXT, SERVICE_SELECT_NEXT_SCHEMA,
lambda entity, call: entity.async_offset_index(1)
)
hass.services.async_register(
DOMAIN, SERVICE_SELECT_OPTION, async_select_option_service,
schema=SERVICE_SELECT_OPTION_SCHEMA)
component.async_register_entity_service(
SERVICE_SELECT_PREVIOUS, SERVICE_SELECT_PREVIOUS_SCHEMA,
lambda entity, call: entity.async_offset_index(-1)
)
@asyncio.coroutine
def async_select_next_service(call):
"""Handle a calls to the input select next service."""
target_inputs = component.async_extract_from_service(call)
tasks = [input_select.async_offset_index(1)
for input_select in target_inputs]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SELECT_NEXT, async_select_next_service,
schema=SERVICE_SELECT_NEXT_SCHEMA)
@asyncio.coroutine
def async_select_previous_service(call):
"""Handle a calls to the input select previous service."""
target_inputs = component.async_extract_from_service(call)
tasks = [input_select.async_offset_index(-1)
for input_select in target_inputs]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SELECT_PREVIOUS, async_select_previous_service,
schema=SERVICE_SELECT_PREVIOUS_SCHEMA)
@asyncio.coroutine
def async_set_options_service(call):
"""Handle a calls to the set options service."""
target_inputs = component.async_extract_from_service(call)
tasks = [input_select.async_set_options(call.data[ATTR_OPTIONS])
for input_select in target_inputs]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_OPTIONS, async_set_options_service,
schema=SERVICE_SET_OPTIONS_SCHEMA)
component.async_register_entity_service(
SERVICE_SET_OPTIONS, SERVICE_SET_OPTIONS_SCHEMA,
'async_set_options'
)
yield from component.async_add_entities(entities)
return True

View file

@ -107,19 +107,10 @@ def async_setup(hass, config):
if not entities:
return False
@asyncio.coroutine
def async_set_value_service(call):
"""Handle a calls to the input box services."""
target_inputs = component.async_extract_from_service(call)
tasks = [input_text.async_set_value(call.data[ATTR_VALUE])
for input_text in target_inputs]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_VALUE, async_set_value_service,
schema=SERVICE_SET_VALUE_SCHEMA)
component.async_register_entity_service(
SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA,
'async_set_value'
)
yield from component.async_add_entities(entities)
return True

View file

@ -101,38 +101,18 @@ def async_setup(hass, config):
yield from component.async_setup(config)
@asyncio.coroutine
def async_handle_lock_service(service):
"""Handle calls to the lock services."""
target_locks = component.async_extract_from_service(service)
code = service.data.get(ATTR_CODE)
update_tasks = []
for entity in target_locks:
if service.service == SERVICE_LOCK:
yield from entity.async_lock(code=code)
elif service.service == SERVICE_OPEN:
yield from entity.async_open(code=code)
else:
yield from entity.async_unlock(code=code)
if not entity.should_poll:
continue
update_tasks.append(entity.async_update_ha_state(True))
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_UNLOCK, async_handle_lock_service,
schema=LOCK_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_LOCK, async_handle_lock_service,
schema=LOCK_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_OPEN, async_handle_lock_service,
schema=LOCK_SERVICE_SCHEMA)
component.async_register_entity_service(
SERVICE_UNLOCK, LOCK_SERVICE_SCHEMA,
'async_unlock'
)
component.async_register_entity_service(
SERVICE_LOCK, LOCK_SERVICE_SCHEMA,
'async_lock'
)
component.async_register_entity_service(
SERVICE_OPEN, LOCK_SERVICE_SCHEMA,
'async_open'
)
return True

View file

@ -134,42 +134,25 @@ def async_setup(hass, config):
_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_REMOTES)
yield from component.async_setup(config)
@asyncio.coroutine
def async_handle_remote_service(service):
"""Handle calls to the remote services."""
target_remotes = component.async_extract_from_service(service)
kwargs = service.data.copy()
component.async_register_entity_service(
SERVICE_TURN_OFF, REMOTE_SERVICE_ACTIVITY_SCHEMA,
'async_turn_off'
)
update_tasks = []
for remote in target_remotes:
if service.service == SERVICE_TURN_ON:
yield from remote.async_turn_on(**kwargs)
elif service.service == SERVICE_TOGGLE:
yield from remote.async_toggle(**kwargs)
elif service.service == SERVICE_SEND_COMMAND:
yield from remote.async_send_command(**kwargs)
else:
yield from remote.async_turn_off(**kwargs)
component.async_register_entity_service(
SERVICE_TURN_ON, REMOTE_SERVICE_ACTIVITY_SCHEMA,
'async_turn_on'
)
if not remote.should_poll:
continue
update_tasks.append(remote.async_update_ha_state(True))
component.async_register_entity_service(
SERVICE_TOGGLE, REMOTE_SERVICE_ACTIVITY_SCHEMA,
'async_toggle'
)
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_handle_remote_service,
schema=REMOTE_SERVICE_ACTIVITY_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_handle_remote_service,
schema=REMOTE_SERVICE_ACTIVITY_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TOGGLE, async_handle_remote_service,
schema=REMOTE_SERVICE_ACTIVITY_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_SEND_COMMAND, async_handle_remote_service,
schema=REMOTE_SERVICE_SEND_COMMAND_SCHEMA)
component.async_register_entity_service(
SERVICE_SEND_COMMAND, REMOTE_SERVICE_SEND_COMMAND_SCHEMA,
'async_send_command'
)
return True

View file

@ -4,7 +4,6 @@ Component to interface with various switches that can be controlled remotely.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/switch/
"""
import asyncio
from datetime import timedelta
import logging
@ -99,36 +98,20 @@ async def async_setup(hass, config):
_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_SWITCHES)
await component.async_setup(config)
async def async_handle_switch_service(service):
"""Handle calls to the switch services."""
target_switches = component.async_extract_from_service(service)
component.async_register_entity_service(
SERVICE_TURN_OFF, SWITCH_SERVICE_SCHEMA,
'async_turn_off'
)
update_tasks = []
for switch in target_switches:
if service.service == SERVICE_TURN_ON:
await switch.async_turn_on()
elif service.service == SERVICE_TOGGLE:
await switch.async_toggle()
else:
await switch.async_turn_off()
component.async_register_entity_service(
SERVICE_TURN_ON, SWITCH_SERVICE_SCHEMA,
'async_turn_on'
)
if not switch.should_poll:
continue
update_tasks.append(
switch.async_update_ha_state(True, service.context))
if update_tasks:
await asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_handle_switch_service,
schema=SWITCH_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_handle_switch_service,
schema=SWITCH_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TOGGLE, async_handle_switch_service,
schema=SWITCH_SERVICE_SCHEMA)
component.async_register_entity_service(
SERVICE_TOGGLE, SWITCH_SERVICE_SCHEMA,
'async_toggle'
)
return True

View file

@ -4,7 +4,6 @@ Timer component.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/timer/
"""
import asyncio
import logging
from datetime import timedelta
@ -141,39 +140,18 @@ async def async_setup(hass, config):
if not entities:
return False
async def async_handler_service(service):
"""Handle a call to the timer services."""
target_timers = component.async_extract_from_service(service)
attr = None
if service.service == SERVICE_PAUSE:
attr = 'async_pause'
elif service.service == SERVICE_CANCEL:
attr = 'async_cancel'
elif service.service == SERVICE_FINISH:
attr = 'async_finish'
tasks = [getattr(timer, attr)() for timer in target_timers if attr]
if service.service == SERVICE_START:
for timer in target_timers:
tasks.append(
timer.async_start(service.data.get(ATTR_DURATION))
)
if tasks:
await asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_START, async_handler_service,
schema=SERVICE_SCHEMA_DURATION)
hass.services.async_register(
DOMAIN, SERVICE_PAUSE, async_handler_service,
schema=SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_CANCEL, async_handler_service,
schema=SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_FINISH, async_handler_service,
schema=SERVICE_SCHEMA)
component.async_register_entity_service(
SERVICE_START, SERVICE_SCHEMA_DURATION,
'async_start')
component.async_register_entity_service(
SERVICE_PAUSE, SERVICE_SCHEMA,
'async_pause')
component.async_register_entity_service(
SERVICE_CANCEL, SERVICE_SCHEMA,
'async_cancel')
component.async_register_entity_service(
SERVICE_FINISH, SERVICE_SCHEMA,
'async_finish')
await component.async_add_entities(entities)
return True

View file

@ -62,23 +62,6 @@ VACUUM_SEND_COMMAND_SERVICE_SCHEMA = VACUUM_SERVICE_SCHEMA.extend({
vol.Optional(ATTR_PARAMS): vol.Any(dict, cv.ensure_list),
})
SERVICE_TO_METHOD = {
SERVICE_TURN_ON: {'method': 'async_turn_on'},
SERVICE_TURN_OFF: {'method': 'async_turn_off'},
SERVICE_TOGGLE: {'method': 'async_toggle'},
SERVICE_START_PAUSE: {'method': 'async_start_pause'},
SERVICE_START: {'method': 'async_start'},
SERVICE_PAUSE: {'method': 'async_pause'},
SERVICE_RETURN_TO_BASE: {'method': 'async_return_to_base'},
SERVICE_CLEAN_SPOT: {'method': 'async_clean_spot'},
SERVICE_LOCATE: {'method': 'async_locate'},
SERVICE_STOP: {'method': 'async_stop'},
SERVICE_SET_FAN_SPEED: {'method': 'async_set_fan_speed',
'schema': VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA},
SERVICE_SEND_COMMAND: {'method': 'async_send_command',
'schema': VACUUM_SEND_COMMAND_SERVICE_SCHEMA},
}
STATE_CLEANING = 'cleaning'
STATE_DOCKED = 'docked'
STATE_IDLE = STATE_IDLE
@ -207,30 +190,54 @@ def async_setup(hass, config):
yield from component.async_setup(config)
@asyncio.coroutine
def async_handle_vacuum_service(service):
"""Map services to methods on VacuumDevice."""
method = SERVICE_TO_METHOD.get(service.service)
target_vacuums = component.async_extract_from_service(service)
params = service.data.copy()
params.pop(ATTR_ENTITY_ID, None)
update_tasks = []
for vacuum in target_vacuums:
yield from getattr(vacuum, method['method'])(**params)
if not vacuum.should_poll:
continue
update_tasks.append(vacuum.async_update_ha_state(True))
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
for service in SERVICE_TO_METHOD:
schema = SERVICE_TO_METHOD[service].get(
'schema', VACUUM_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, service, async_handle_vacuum_service,
schema=schema)
component.async_register_entity_service(
SERVICE_TURN_ON, VACUUM_SERVICE_SCHEMA,
'async_turn_on'
)
component.async_register_entity_service(
SERVICE_TURN_OFF, VACUUM_SERVICE_SCHEMA,
'async_turn_off'
)
component.async_register_entity_service(
SERVICE_TOGGLE, VACUUM_SERVICE_SCHEMA,
'async_toggle'
)
component.async_register_entity_service(
SERVICE_START_PAUSE, VACUUM_SERVICE_SCHEMA,
'async_start_pause'
)
component.async_register_entity_service(
SERVICE_START, VACUUM_SERVICE_SCHEMA,
'async_start'
)
component.async_register_entity_service(
SERVICE_PAUSE, VACUUM_SERVICE_SCHEMA,
'async_pause'
)
component.async_register_entity_service(
SERVICE_RETURN_TO_BASE, VACUUM_SERVICE_SCHEMA,
'async_return_to_base'
)
component.async_register_entity_service(
SERVICE_CLEAN_SPOT, VACUUM_SERVICE_SCHEMA,
'async_clean_spot'
)
component.async_register_entity_service(
SERVICE_LOCATE, VACUUM_SERVICE_SCHEMA,
'async_locate'
)
component.async_register_entity_service(
SERVICE_STOP, VACUUM_SERVICE_SCHEMA,
'async_stop'
)
component.async_register_entity_service(
SERVICE_SET_FAN_SPEED, VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA,
'async_set_fan_speed'
)
component.async_register_entity_service(
SERVICE_SEND_COMMAND, VACUUM_SEND_COMMAND_SERVICE_SCHEMA,
'async_send_command'
)
return True

View file

@ -142,6 +142,18 @@ class EntityComponent:
return [entity for entity in self.entities
if entity.available and entity.entity_id in entity_ids]
@callback
def async_register_entity_service(self, name, schema, func):
"""Register an entity service."""
async def handle_service(call):
"""Handle the service."""
await self.hass.helpers.service.entity_service_call(
self._platforms.values(), func, call
)
self.hass.services.async_register(
self.domain, name, handle_service, schema)
async def _async_setup_platform(self, platform_type, platform_config,
discovery_info=None):
"""Set up a platform for this component."""

View file

@ -1,4 +1,5 @@
"""Service calling related helpers."""
import asyncio
import logging
from os import path
@ -178,3 +179,52 @@ async def async_get_all_descriptions(hass):
descriptions[domain][service] = description
return descriptions
@bind_hass
async def entity_service_call(hass, platforms, func, call):
"""Handle an entity service call.
Calls all platforms simultaneously.
"""
tasks = []
all_entities = ATTR_ENTITY_ID not in call.data
if not all_entities:
entity_ids = set(
extract_entity_ids(hass, call, True))
if isinstance(func, str):
data = {key: val for key, val in call.data.items()
if key != ATTR_ENTITY_ID}
else:
data = call
tasks = [
_handle_service_platform_call(func, data, [
entity for entity in platform.entities.values()
if all_entities or entity.entity_id in entity_ids
], call.context) for platform in platforms
]
if tasks:
await asyncio.wait(tasks)
async def _handle_service_platform_call(func, data, entities, context):
"""Handle a function call."""
tasks = []
for entity in entities:
if not entity.available:
continue
if isinstance(func, str):
await getattr(entity, func)(**data)
else:
await func(entity, data)
if entity.should_poll:
tasks.append(entity.async_update_ha_state(True, context))
if tasks:
await asyncio.wait(tasks)