diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 0a4dd6bde78..f9f2a4e03be 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -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 diff --git a/homeassistant/components/counter/__init__.py b/homeassistant/components/counter/__init__.py index 03e5b273468..d720819a0ab 100644 --- a/homeassistant/components/counter/__init__.py +++ b/homeassistant/components/counter/__init__.py @@ -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 diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index f5d3d798e2e..05c5e46e44e 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -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 {}")) diff --git a/homeassistant/components/input_boolean.py b/homeassistant/components/input_boolean.py index 9c8435614a2..b9c4dcc685e 100644 --- a/homeassistant/components/input_boolean.py +++ b/homeassistant/components/input_boolean.py @@ -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 diff --git a/homeassistant/components/input_number.py b/homeassistant/components/input_number.py index e18169fca73..2f25ca143b8 100644 --- a/homeassistant/components/input_number.py +++ b/homeassistant/components/input_number.py @@ -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 diff --git a/homeassistant/components/input_select.py b/homeassistant/components/input_select.py index f16b029c1d7..04e9b04787c 100644 --- a/homeassistant/components/input_select.py +++ b/homeassistant/components/input_select.py @@ -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 diff --git a/homeassistant/components/input_text.py b/homeassistant/components/input_text.py index 6433a01fb6d..2cb4f58a130 100644 --- a/homeassistant/components/input_text.py +++ b/homeassistant/components/input_text.py @@ -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 diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index f03d028a38f..3c4ff7cdedd 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -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 diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index ddae36b92a7..11ecb20f7aa 100644 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -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 diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index cb69240ee73..3ca52a91758 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -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 diff --git a/homeassistant/components/timer/__init__.py b/homeassistant/components/timer/__init__.py index 5a363e84d7b..8406b3ff5ec 100644 --- a/homeassistant/components/timer/__init__.py +++ b/homeassistant/components/timer/__init__.py @@ -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 diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 97d009626b8..1808737d281 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -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 diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 72b6ceecbfd..cf035095a84 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -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.""" diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 8aa3b553f3a..acad72a860a 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -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)