From 02d9ed5e36257490726a75c8440b4a2b61bc7fe4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 2 Dec 2019 16:23:12 -0800 Subject: [PATCH] Do not select all entities when omitting entity ID in service call (#29178) * Do not select all entities when omitting entity ID * Address comments Matthew * Require either area_id or entity_id * Fix tests * Fix test --- .../alarm_control_panel/__init__.py | 6 +- .../components/automation/__init__.py | 14 ++- homeassistant/components/climate/__init__.py | 81 ++++++++--------- homeassistant/components/counter/__init__.py | 32 +++---- homeassistant/components/cover/__init__.py | 51 +++++------ homeassistant/components/fan/__init__.py | 39 +++----- homeassistant/components/group/__init__.py | 50 +++++------ .../components/image_processing/__init__.py | 4 +- .../components/input_boolean/__init__.py | 13 +-- .../components/input_datetime/__init__.py | 17 ++-- .../components/input_number/__init__.py | 17 ++-- .../components/input_select/__init__.py | 32 +++---- .../components/input_text/__init__.py | 7 +- homeassistant/components/lifx/light.py | 18 ++-- homeassistant/components/light/__init__.py | 77 ++++++++-------- homeassistant/components/lock/__init__.py | 4 +- .../components/media_extractor/__init__.py | 10 ++- .../components/media_player/__init__.py | 90 ++++++------------- homeassistant/components/remote/__init__.py | 42 ++++----- homeassistant/components/script/__init__.py | 4 +- homeassistant/components/timer/__init__.py | 25 +++--- .../components/utility_meter/__init__.py | 18 ++-- homeassistant/components/vacuum/__init__.py | 57 ++++-------- homeassistant/components/wink/__init__.py | 22 ++--- homeassistant/helpers/config_validation.py | 23 +++-- homeassistant/helpers/entity_component.py | 18 ++-- homeassistant/helpers/service.py | 14 +-- .../components/alarm_control_panel/common.py | 25 +++--- tests/components/automation/common.py | 9 +- tests/components/camera/common.py | 15 ++-- tests/components/climate/common.py | 33 +++---- tests/components/demo/test_light.py | 8 +- tests/components/fan/common.py | 17 ++-- tests/components/image_processing/common.py | 6 +- tests/components/light/common.py | 13 +-- tests/components/lock/common.py | 13 +-- tests/components/media_player/common.py | 35 ++++---- tests/components/mqtt/test_state_vacuum.py | 49 +++++++--- tests/components/remote/common.py | 25 ++++-- tests/components/scene/common.py | 4 +- tests/components/smartthings/test_climate.py | 8 +- tests/components/smartthings/test_cover.py | 10 ++- tests/components/switch/common.py | 15 ++-- tests/components/vacuum/common.py | 49 +++++----- tests/components/water_heater/common.py | 10 ++- tests/helpers/test_entity_component.py | 12 ++- tests/helpers/test_service.py | 23 +++-- 47 files changed, 538 insertions(+), 626 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 2a335651d96..dfac0fd192f 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -17,7 +17,7 @@ from homeassistant.const import ( ) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, + make_entity_service_schema, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -41,9 +41,7 @@ ATTR_CODE_ARM_REQUIRED = "code_arm_required" ENTITY_ID_FORMAT = DOMAIN + ".{}" -ALARM_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Optional(ATTR_CODE): cv.string} -) +ALARM_SERVICE_SCHEMA = make_entity_service_schema({vol.Optional(ATTR_CODE): cv.string}) async def async_setup(hass, config): diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 3409ce832dd..3863ab0c88d 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -24,7 +24,7 @@ from homeassistant.core import Context, CoreState, HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import condition, extract_domain_configs, script import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity @@ -106,7 +106,7 @@ PLATFORM_SCHEMA = vol.Schema( } ) -TRIGGER_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +TRIGGER_SERVICE_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_VARIABLES, default={}): dict} ) @@ -184,12 +184,18 @@ async def async_setup(hass, config): ) hass.services.async_register( - DOMAIN, SERVICE_TOGGLE, toggle_service_handler, schema=ENTITY_SERVICE_SCHEMA + DOMAIN, + SERVICE_TOGGLE, + toggle_service_handler, + schema=make_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 + DOMAIN, + service, + turn_onoff_service_handler, + schema=make_entity_service_schema({}), ) return True diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 4d58e1811be..6006b2a9a3b 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -19,7 +19,7 @@ from homeassistant.const import ( ) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, + make_entity_service_schema, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -84,38 +84,19 @@ CONVERTIBLE_ATTRIBUTE = [ATTR_TEMPERATURE, ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEM _LOGGER = logging.getLogger(__name__) -SET_AUX_HEAT_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_AUX_HEAT): cv.boolean} -) -SET_TEMPERATURE_SCHEMA = vol.Schema( - vol.All( - cv.has_at_least_one_key( - ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW - ), - ENTITY_SERVICE_SCHEMA.extend( - { - 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), - } - ), - ) -) -SET_FAN_MODE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_FAN_MODE): cv.string} -) -SET_PRESET_MODE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_PRESET_MODE): cv.string} -) -SET_HVAC_MODE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_HVAC_MODE): vol.In(HVAC_MODES)} -) -SET_HUMIDITY_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_HUMIDITY): vol.Coerce(float)} -) -SET_SWING_MODE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_SWING_MODE): cv.string} + +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), + } + ), ) @@ -126,32 +107,40 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: ) await component.async_setup(config) + component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on") + component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") component.async_register_entity_service( - SERVICE_TURN_ON, ENTITY_SERVICE_SCHEMA, "async_turn_on" + SERVICE_SET_HVAC_MODE, + {vol.Required(ATTR_HVAC_MODE): vol.In(HVAC_MODES)}, + "async_set_hvac_mode", ) component.async_register_entity_service( - SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off" + SERVICE_SET_PRESET_MODE, + {vol.Required(ATTR_PRESET_MODE): cv.string}, + "async_set_preset_mode", ) component.async_register_entity_service( - SERVICE_SET_HVAC_MODE, SET_HVAC_MODE_SCHEMA, "async_set_hvac_mode" + SERVICE_SET_AUX_HEAT, + {vol.Required(ATTR_AUX_HEAT): cv.boolean}, + async_service_aux_heat, ) component.async_register_entity_service( - SERVICE_SET_PRESET_MODE, SET_PRESET_MODE_SCHEMA, "async_set_preset_mode" + SERVICE_SET_TEMPERATURE, SET_TEMPERATURE_SCHEMA, async_service_temperature_set, ) component.async_register_entity_service( - SERVICE_SET_AUX_HEAT, SET_AUX_HEAT_SCHEMA, async_service_aux_heat + SERVICE_SET_HUMIDITY, + {vol.Required(ATTR_HUMIDITY): vol.Coerce(float)}, + "async_set_humidity", ) component.async_register_entity_service( - SERVICE_SET_TEMPERATURE, SET_TEMPERATURE_SCHEMA, async_service_temperature_set + SERVICE_SET_FAN_MODE, + {vol.Required(ATTR_FAN_MODE): cv.string}, + "async_set_fan_mode", ) component.async_register_entity_service( - SERVICE_SET_HUMIDITY, SET_HUMIDITY_SCHEMA, "async_set_humidity" - ) - component.async_register_entity_service( - SERVICE_SET_FAN_MODE, SET_FAN_MODE_SCHEMA, "async_set_fan_mode" - ) - component.async_register_entity_service( - SERVICE_SET_SWING_MODE, SET_SWING_MODE_SCHEMA, "async_set_swing_mode" + SERVICE_SET_SWING_MODE, + {vol.Required(ATTR_SWING_MODE): cv.string}, + "async_set_swing_mode", ) return True diff --git a/homeassistant/components/counter/__init__.py b/homeassistant/components/counter/__init__.py index aca3461b4f7..c2f61d0c1b4 100644 --- a/homeassistant/components/counter/__init__.py +++ b/homeassistant/components/counter/__init__.py @@ -6,7 +6,6 @@ import voluptuous as vol from homeassistant.const import CONF_ICON, CONF_NAME, CONF_MAXIMUM, CONF_MINIMUM import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity @@ -33,15 +32,6 @@ SERVICE_INCREMENT = "increment" SERVICE_RESET = "reset" SERVICE_CONFIGURE = "configure" -SERVICE_SCHEMA_CONFIGURE = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Optional(ATTR_MINIMUM): vol.Any(None, vol.Coerce(int)), - vol.Optional(ATTR_MAXIMUM): vol.Any(None, vol.Coerce(int)), - vol.Optional(ATTR_STEP): cv.positive_int, - vol.Optional(ATTR_INITIAL): cv.positive_int, - vol.Optional(VALUE): cv.positive_int, - } -) CONFIG_SCHEMA = vol.Schema( { @@ -95,17 +85,19 @@ async def async_setup(hass, config): if not entities: return False + component.async_register_entity_service(SERVICE_INCREMENT, {}, "async_increment") + component.async_register_entity_service(SERVICE_DECREMENT, {}, "async_decrement") + component.async_register_entity_service(SERVICE_RESET, {}, "async_reset") component.async_register_entity_service( - SERVICE_INCREMENT, ENTITY_SERVICE_SCHEMA, "async_increment" - ) - component.async_register_entity_service( - SERVICE_DECREMENT, ENTITY_SERVICE_SCHEMA, "async_decrement" - ) - component.async_register_entity_service( - SERVICE_RESET, ENTITY_SERVICE_SCHEMA, "async_reset" - ) - component.async_register_entity_service( - SERVICE_CONFIGURE, SERVICE_SCHEMA_CONFIGURE, "async_configure" + SERVICE_CONFIGURE, + { + vol.Optional(ATTR_MINIMUM): vol.Any(None, vol.Coerce(int)), + vol.Optional(ATTR_MAXIMUM): vol.Any(None, vol.Coerce(int)), + vol.Optional(ATTR_STEP): cv.positive_int, + vol.Optional(ATTR_INITIAL): cv.positive_int, + vol.Optional(VALUE): cv.positive_int, + }, + "async_configure", ) await component.async_add_entities(entities) diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index a3c28a77cbe..d7fc0c49742 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -13,7 +13,6 @@ from homeassistant.helpers.config_validation import ( # noqa: F401 PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.components import group from homeassistant.const import ( SERVICE_OPEN_COVER, @@ -83,18 +82,6 @@ ATTR_POSITION = "position" ATTR_TILT_POSITION = "tilt_position" -COVER_SET_COVER_POSITION_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_POSITION): vol.All(vol.Coerce(int), vol.Range(min=0, max=100))} -) - -COVER_SET_COVER_TILT_POSITION_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Required(ATTR_TILT_POSITION): vol.All( - vol.Coerce(int), vol.Range(min=0, max=100) - ) - } -) - @bind_hass def is_closed(hass, entity_id=None): @@ -111,48 +98,50 @@ async def async_setup(hass, config): await component.async_setup(config) - component.async_register_entity_service( - SERVICE_OPEN_COVER, ENTITY_SERVICE_SCHEMA, "async_open_cover" - ) + component.async_register_entity_service(SERVICE_OPEN_COVER, {}, "async_open_cover") component.async_register_entity_service( - SERVICE_CLOSE_COVER, ENTITY_SERVICE_SCHEMA, "async_close_cover" + SERVICE_CLOSE_COVER, {}, "async_close_cover" ) component.async_register_entity_service( SERVICE_SET_COVER_POSITION, - COVER_SET_COVER_POSITION_SCHEMA, + { + vol.Required(ATTR_POSITION): vol.All( + vol.Coerce(int), vol.Range(min=0, max=100) + ) + }, "async_set_cover_position", ) + component.async_register_entity_service(SERVICE_STOP_COVER, {}, "async_stop_cover") + + component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") + component.async_register_entity_service( - SERVICE_STOP_COVER, ENTITY_SERVICE_SCHEMA, "async_stop_cover" + SERVICE_OPEN_COVER_TILT, {}, "async_open_cover_tilt" ) component.async_register_entity_service( - SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle" + SERVICE_CLOSE_COVER_TILT, {}, "async_close_cover_tilt" ) component.async_register_entity_service( - SERVICE_OPEN_COVER_TILT, ENTITY_SERVICE_SCHEMA, "async_open_cover_tilt" - ) - - component.async_register_entity_service( - SERVICE_CLOSE_COVER_TILT, ENTITY_SERVICE_SCHEMA, "async_close_cover_tilt" - ) - - component.async_register_entity_service( - SERVICE_STOP_COVER_TILT, ENTITY_SERVICE_SCHEMA, "async_stop_cover_tilt" + SERVICE_STOP_COVER_TILT, {}, "async_stop_cover_tilt" ) component.async_register_entity_service( SERVICE_SET_COVER_TILT_POSITION, - COVER_SET_COVER_TILT_POSITION_SCHEMA, + { + vol.Required(ATTR_TILT_POSITION): vol.All( + vol.Coerce(int), vol.Range(min=0, max=100) + ) + }, "async_set_cover_tilt_position", ) component.async_register_entity_service( - SERVICE_TOGGLE_COVER_TILT, ENTITY_SERVICE_SCHEMA, "async_toggle_tilt" + SERVICE_TOGGLE_COVER_TILT, {}, "async_toggle_tilt" ) return True diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index 4c6cee2927c..51aecc3e7c2 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -12,7 +12,6 @@ from homeassistant.loader import bind_hass from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -57,20 +56,6 @@ PROP_TO_ATTR = { "current_direction": ATTR_DIRECTION, } -FAN_SET_SPEED_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_SPEED): cv.string} -) - -FAN_TURN_ON_SCHEMA = ENTITY_SERVICE_SCHEMA.extend({vol.Optional(ATTR_SPEED): cv.string}) - -FAN_OSCILLATE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_OSCILLATING): cv.boolean} -) - -FAN_SET_DIRECTION_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Optional(ATTR_DIRECTION): cv.string} -) - @bind_hass def is_on(hass, entity_id: Optional[str] = None) -> bool: @@ -89,22 +74,22 @@ async def async_setup(hass, config: dict): await component.async_setup(config) component.async_register_entity_service( - SERVICE_TURN_ON, FAN_TURN_ON_SCHEMA, "async_turn_on" + SERVICE_TURN_ON, {vol.Optional(ATTR_SPEED): cv.string}, "async_turn_on" + ) + component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") + component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") + component.async_register_entity_service( + SERVICE_SET_SPEED, {vol.Required(ATTR_SPEED): cv.string}, "async_set_speed" ) component.async_register_entity_service( - SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off" + SERVICE_OSCILLATE, + {vol.Required(ATTR_OSCILLATING): cv.boolean}, + "async_oscillate", ) component.async_register_entity_service( - SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle" - ) - component.async_register_entity_service( - SERVICE_SET_SPEED, FAN_SET_SPEED_SCHEMA, "async_set_speed" - ) - component.async_register_entity_service( - SERVICE_OSCILLATE, FAN_OSCILLATE_SCHEMA, "async_oscillate" - ) - component.async_register_entity_service( - SERVICE_SET_DIRECTION, FAN_SET_DIRECTION_SCHEMA, "async_set_direction" + SERVICE_SET_DIRECTION, + {vol.Optional(ATTR_DIRECTION): cv.string}, + "async_set_direction", ) return True diff --git a/homeassistant/components/group/__init__.py b/homeassistant/components/group/__init__.py index b4688229073..ba12e22b53e 100644 --- a/homeassistant/components/group/__init__.py +++ b/homeassistant/components/group/__init__.py @@ -32,7 +32,7 @@ from homeassistant.helpers.entity import Entity, async_generate_entity_id from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.event import async_track_state_change import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.typing import HomeAssistantType @@ -63,28 +63,6 @@ SERVICE_REMOVE = "remove" CONTROL_TYPES = vol.In(["hidden", None]) -SET_VISIBILITY_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_VISIBLE): cv.boolean} -) - -RELOAD_SERVICE_SCHEMA = vol.Schema({}) - -SET_SERVICE_SCHEMA = 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, - } -) - -REMOVE_SERVICE_SCHEMA = vol.Schema({vol.Required(ATTR_OBJECT_ID): cv.slug}) - _LOGGER = logging.getLogger(__name__) @@ -227,7 +205,7 @@ async def async_setup(hass, config): await component.async_add_entities(auto) hass.services.async_register( - DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA + DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=vol.Schema({}) ) service_lock = asyncio.Lock() @@ -319,11 +297,29 @@ async def async_setup(hass, config): await component.async_remove_entity(entity_id) hass.services.async_register( - DOMAIN, SERVICE_SET, locked_service_handler, schema=SET_SERVICE_SCHEMA + DOMAIN, + SERVICE_SET, + locked_service_handler, + schema=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, + } + ), ) hass.services.async_register( - DOMAIN, SERVICE_REMOVE, groups_service_handler, schema=REMOVE_SERVICE_SCHEMA + DOMAIN, + SERVICE_REMOVE, + groups_service_handler, + schema=vol.Schema({vol.Required(ATTR_OBJECT_ID): cv.slug}), ) async def visibility_service_handler(service): @@ -344,7 +340,7 @@ async def async_setup(hass, config): DOMAIN, SERVICE_SET_VISIBILITY, visibility_service_handler, - schema=SET_VISIBILITY_SERVICE_SCHEMA, + schema=make_entity_service_schema({vol.Required(ATTR_VISIBLE): cv.boolean}), ) return True diff --git a/homeassistant/components/image_processing/__init__.py b/homeassistant/components/image_processing/__init__.py index 4c90441e7f0..78ae15eb537 100644 --- a/homeassistant/components/image_processing/__init__.py +++ b/homeassistant/components/image_processing/__init__.py @@ -11,7 +11,7 @@ from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME, CONF_ENTITY_ID, CONF_ from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.util.async_ import run_callback_threadsafe @@ -124,7 +124,7 @@ async def async_setup(hass, config): await asyncio.wait(update_tasks) hass.services.async_register( - DOMAIN, SERVICE_SCAN, async_scan_service, schema=ENTITY_SERVICE_SCHEMA + DOMAIN, SERVICE_SCAN, async_scan_service, schema=make_entity_service_schema({}) ) return True diff --git a/homeassistant/components/input_boolean/__init__.py b/homeassistant/components/input_boolean/__init__.py index 6027b0b3da1..4a32ad16797 100644 --- a/homeassistant/components/input_boolean/__init__.py +++ b/homeassistant/components/input_boolean/__init__.py @@ -13,7 +13,6 @@ from homeassistant.const import ( ) from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity @@ -68,17 +67,11 @@ async def async_setup(hass, config): if not entities: return False - component.async_register_entity_service( - SERVICE_TURN_ON, ENTITY_SERVICE_SCHEMA, "async_turn_on" - ) + component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on") - component.async_register_entity_service( - SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off" - ) + component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") - component.async_register_entity_service( - SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle" - ) + component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") await component.async_add_entities(entities) return True diff --git a/homeassistant/components/input_datetime/__init__.py b/homeassistant/components/input_datetime/__init__.py index c366be90b14..36180ed2bad 100644 --- a/homeassistant/components/input_datetime/__init__.py +++ b/homeassistant/components/input_datetime/__init__.py @@ -6,7 +6,6 @@ import voluptuous as vol from homeassistant.const import ATTR_DATE, ATTR_TIME, CONF_ICON, CONF_NAME import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.util import dt as dt_util @@ -27,14 +26,6 @@ ATTR_DATETIME = "datetime" SERVICE_SET_DATETIME = "set_datetime" -SERVICE_SET_DATETIME_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Optional(ATTR_DATE): cv.date, - vol.Optional(ATTR_TIME): cv.time, - vol.Optional(ATTR_DATETIME): cv.datetime, - } -) - def has_date_or_time(conf): """Check at least date or time is true.""" @@ -108,7 +99,13 @@ async def async_setup(hass, config): entity.async_set_datetime(date, time) component.async_register_entity_service( - SERVICE_SET_DATETIME, SERVICE_SET_DATETIME_SCHEMA, async_set_datetime_service + SERVICE_SET_DATETIME, + { + vol.Optional(ATTR_DATE): cv.date, + vol.Optional(ATTR_TIME): cv.time, + vol.Optional(ATTR_DATETIME): cv.datetime, + }, + async_set_datetime_service, ) await component.async_add_entities(entities) diff --git a/homeassistant/components/input_number/__init__.py b/homeassistant/components/input_number/__init__.py index 9b4d5a961ba..77625ffa7f8 100644 --- a/homeassistant/components/input_number/__init__.py +++ b/homeassistant/components/input_number/__init__.py @@ -4,7 +4,6 @@ import logging import voluptuous as vol import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, ATTR_MODE, @@ -38,10 +37,6 @@ SERVICE_SET_VALUE = "set_value" SERVICE_INCREMENT = "increment" SERVICE_DECREMENT = "decrement" -SERVICE_SET_VALUE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_VALUE): vol.Coerce(float)} -) - def _cv_input_number(cfg): """Configure validation helper for input number (voluptuous).""" @@ -110,16 +105,14 @@ async def async_setup(hass, config): return False component.async_register_entity_service( - SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA, "async_set_value" + SERVICE_SET_VALUE, + {vol.Required(ATTR_VALUE): vol.Coerce(float)}, + "async_set_value", ) - component.async_register_entity_service( - SERVICE_INCREMENT, ENTITY_SERVICE_SCHEMA, "async_increment" - ) + component.async_register_entity_service(SERVICE_INCREMENT, {}, "async_increment") - component.async_register_entity_service( - SERVICE_DECREMENT, ENTITY_SERVICE_SCHEMA, "async_decrement" - ) + component.async_register_entity_service(SERVICE_DECREMENT, {}, "async_decrement") await component.async_add_entities(entities) return True diff --git a/homeassistant/components/input_select/__init__.py b/homeassistant/components/input_select/__init__.py index 8cb3001c52e..ae609e09271 100644 --- a/homeassistant/components/input_select/__init__.py +++ b/homeassistant/components/input_select/__init__.py @@ -5,7 +5,6 @@ import voluptuous as vol from homeassistant.const import CONF_ICON, CONF_NAME import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity @@ -22,9 +21,6 @@ ATTR_OPTIONS = "options" SERVICE_SELECT_OPTION = "select_option" -SERVICE_SELECT_OPTION_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_OPTION): cv.string} -) SERVICE_SELECT_NEXT = "select_next" @@ -32,14 +28,6 @@ SERVICE_SELECT_PREVIOUS = "select_previous" SERVICE_SET_OPTIONS = "set_options" -SERVICE_SET_OPTIONS_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Required(ATTR_OPTIONS): vol.All( - cv.ensure_list, vol.Length(min=1), [cv.string] - ) - } -) - def _cv_input_select(cfg): """Configure validation helper for input select (voluptuous).""" @@ -92,23 +80,27 @@ async def async_setup(hass, config): return False component.async_register_entity_service( - SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION_SCHEMA, "async_select_option" + SERVICE_SELECT_OPTION, + {vol.Required(ATTR_OPTION): cv.string}, + "async_select_option", ) component.async_register_entity_service( - SERVICE_SELECT_NEXT, - ENTITY_SERVICE_SCHEMA, - lambda entity, call: entity.async_offset_index(1), + SERVICE_SELECT_NEXT, {}, lambda entity, call: entity.async_offset_index(1), ) component.async_register_entity_service( - SERVICE_SELECT_PREVIOUS, - ENTITY_SERVICE_SCHEMA, - lambda entity, call: entity.async_offset_index(-1), + SERVICE_SELECT_PREVIOUS, {}, lambda entity, call: entity.async_offset_index(-1), ) component.async_register_entity_service( - SERVICE_SET_OPTIONS, SERVICE_SET_OPTIONS_SCHEMA, "async_set_options" + SERVICE_SET_OPTIONS, + { + vol.Required(ATTR_OPTIONS): vol.All( + cv.ensure_list, vol.Length(min=1), [cv.string] + ) + }, + "async_set_options", ) await component.async_add_entities(entities) diff --git a/homeassistant/components/input_text/__init__.py b/homeassistant/components/input_text/__init__.py index 1b4670cf1e6..d43e47c11ca 100644 --- a/homeassistant/components/input_text/__init__.py +++ b/homeassistant/components/input_text/__init__.py @@ -4,7 +4,6 @@ import logging import voluptuous as vol import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, ATTR_MODE, @@ -34,10 +33,6 @@ ATTR_PATTERN = "pattern" SERVICE_SET_VALUE = "set_value" -SERVICE_SET_VALUE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_VALUE): cv.string} -) - def _cv_input_text(cfg): """Configure validation helper for input box (voluptuous).""" @@ -111,7 +106,7 @@ async def async_setup(hass, config): return False component.async_register_entity_service( - SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA, "async_set_value" + SERVICE_SET_VALUE, {vol.Required(ATTR_VALUE): cv.string}, "async_set_value" ) await component.async_add_entities(entities) diff --git a/homeassistant/components/lifx/light.py b/homeassistant/components/lifx/light.py index 7b33e0c1d86..1fb614f856f 100644 --- a/homeassistant/components/lifx/light.py +++ b/homeassistant/components/lifx/light.py @@ -66,8 +66,9 @@ ATTR_INFRARED = "infrared" ATTR_ZONES = "zones" ATTR_POWER = "power" -LIFX_SET_STATE_SCHEMA = LIGHT_TURN_ON_SCHEMA.extend( +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, @@ -369,16 +370,11 @@ class LIFXManager: async def async_service_to_entities(self, service): """Return the known entities that a service call mentions.""" entity_ids = await async_extract_entity_ids(self.hass, service) - if entity_ids: - entities = [ - entity - for entity in self.entities.values() - if entity.entity_id in entity_ids - ] - else: - entities = list(self.entities.values()) - - return entities + return [ + entity + for entity in self.entities.values() + if entity.entity_id in entity_ids + ] @callback def register(self, bulb): diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 7bc2306d418..f01258e2ab4 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -22,7 +22,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import ( # noqa: F401 PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, - ENTITY_SERVICE_SCHEMA, + make_entity_service_schema, ) from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent @@ -93,49 +93,37 @@ VALID_TRANSITION = vol.All(vol.Coerce(float), vol.Clamp(min=0, max=6553)) 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)) -LIGHT_TURN_ON_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Exclusive(ATTR_PROFILE, COLOR_GROUP): cv.string, - ATTR_TRANSITION: VALID_TRANSITION, - ATTR_BRIGHTNESS: VALID_BRIGHTNESS, - ATTR_BRIGHTNESS_PCT: VALID_BRIGHTNESS_PCT, - vol.Exclusive(ATTR_COLOR_NAME, COLOR_GROUP): cv.string, - vol.Exclusive(ATTR_RGB_COLOR, COLOR_GROUP): vol.All( - vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple) - ), - vol.Exclusive(ATTR_XY_COLOR, COLOR_GROUP): vol.All( - vol.ExactSequence((cv.small_float, cv.small_float)), vol.Coerce(tuple) - ), - vol.Exclusive(ATTR_HS_COLOR, COLOR_GROUP): vol.All( - vol.ExactSequence( - ( - vol.All(vol.Coerce(float), vol.Range(min=0, max=360)), - vol.All(vol.Coerce(float), vol.Range(min=0, max=100)), - ) - ), - vol.Coerce(tuple), - ), - vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP): vol.All( - vol.Coerce(int), vol.Range(min=1) - ), - vol.Exclusive(ATTR_KELVIN, COLOR_GROUP): vol.All( - vol.Coerce(int), vol.Range(min=0) - ), - ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)), - ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]), - ATTR_EFFECT: cv.string, - } -) - - -LIGHT_TURN_OFF_SCHEMA = { +LIGHT_TURN_ON_SCHEMA = { + vol.Exclusive(ATTR_PROFILE, COLOR_GROUP): cv.string, ATTR_TRANSITION: VALID_TRANSITION, + ATTR_BRIGHTNESS: VALID_BRIGHTNESS, + ATTR_BRIGHTNESS_PCT: VALID_BRIGHTNESS_PCT, + vol.Exclusive(ATTR_COLOR_NAME, COLOR_GROUP): cv.string, + vol.Exclusive(ATTR_RGB_COLOR, COLOR_GROUP): vol.All( + vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple) + ), + vol.Exclusive(ATTR_XY_COLOR, COLOR_GROUP): vol.All( + vol.ExactSequence((cv.small_float, cv.small_float)), vol.Coerce(tuple) + ), + vol.Exclusive(ATTR_HS_COLOR, COLOR_GROUP): vol.All( + vol.ExactSequence( + ( + vol.All(vol.Coerce(float), vol.Range(min=0, max=360)), + vol.All(vol.Coerce(float), vol.Range(min=0, max=100)), + ) + ), + vol.Coerce(tuple), + ), + vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP): vol.All( + vol.Coerce(int), vol.Range(min=1) + ), + vol.Exclusive(ATTR_KELVIN, COLOR_GROUP): vol.All(vol.Coerce(int), vol.Range(min=0)), + ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)), ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]), + ATTR_EFFECT: cv.string, } -LIGHT_TOGGLE_SCHEMA = LIGHT_TURN_ON_SCHEMA - PROFILE_SCHEMA = vol.Schema( vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)) ) @@ -268,15 +256,20 @@ async def async_setup(hass, config): DOMAIN, SERVICE_TURN_ON, async_handle_light_on_service, - schema=LIGHT_TURN_ON_SCHEMA, + schema=cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA), ) component.async_register_entity_service( - SERVICE_TURN_OFF, LIGHT_TURN_OFF_SCHEMA, "async_turn_off" + 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_TOGGLE_SCHEMA, "async_toggle" + SERVICE_TOGGLE, LIGHT_TURN_ON_SCHEMA, "async_toggle" ) return True diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 341df1bb28a..c443a5219d7 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -9,7 +9,7 @@ from homeassistant.loader import bind_hass from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import Entity from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, + make_entity_service_schema, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -40,7 +40,7 @@ GROUP_NAME_ALL_LOCKS = "all locks" MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) -LOCK_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend({vol.Optional(ATTR_CODE): cv.string}) +LOCK_SERVICE_SCHEMA = make_entity_service_schema({vol.Optional(ATTR_CODE): cv.string}) # Bitfield of features supported by the lock entity SUPPORT_OPEN = 1 diff --git a/homeassistant/components/media_extractor/__init__.py b/homeassistant/components/media_extractor/__init__.py index 97cb7d9978a..7dc05368dcd 100644 --- a/homeassistant/components/media_extractor/__init__.py +++ b/homeassistant/components/media_extractor/__init__.py @@ -2,6 +2,8 @@ import logging import voluptuous as vol +from youtube_dl import YoutubeDL +from youtube_dl.utils import DownloadError, ExtractorError from homeassistant.components.media_player import MEDIA_PLAYER_PLAY_MEDIA_SCHEMA from homeassistant.components.media_player.const import ( @@ -44,7 +46,10 @@ def setup(hass, config): MediaExtractor(hass, config[DOMAIN], call.data).extract_and_send() hass.services.register( - DOMAIN, SERVICE_PLAY_MEDIA, play_media, schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA + DOMAIN, + SERVICE_PLAY_MEDIA, + play_media, + schema=cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA), ) return True @@ -98,9 +103,6 @@ class MediaExtractor: def get_stream_selector(self): """Return format selector for the media URL.""" - from youtube_dl import YoutubeDL - from youtube_dl.utils import DownloadError, ExtractorError - ydl = YoutubeDL({"quiet": True, "logger": _LOGGER}) try: diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index c783772365b..a6cd4dda4ea 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -40,7 +40,6 @@ from homeassistant.const import ( from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -123,42 +122,12 @@ DEVICE_CLASSES = [DEVICE_CLASS_TV, DEVICE_CLASS_SPEAKER] DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) -# Service call validation schemas -MEDIA_PLAYER_SET_VOLUME_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float} -) -MEDIA_PLAYER_MUTE_VOLUME_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean} -) - -MEDIA_PLAYER_MEDIA_SEEK_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Required(ATTR_MEDIA_SEEK_POSITION): vol.All( - vol.Coerce(float), vol.Range(min=0) - ) - } -) - -MEDIA_PLAYER_SELECT_SOURCE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_INPUT_SOURCE): cv.string} -) - -MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_SOUND_MODE): cv.string} -) - -MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string, - vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string, - vol.Optional(ATTR_MEDIA_ENQUEUE): cv.boolean, - } -) - -MEDIA_PLAYER_SET_SHUFFLE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean} -) +MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = { + vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string, + vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string, + vol.Optional(ATTR_MEDIA_ENQUEUE): cv.boolean, +} ATTR_TO_PROPERTY = [ ATTR_MEDIA_VOLUME_LEVEL, @@ -223,65 +192,56 @@ async def async_setup(hass, config): await component.async_setup(config) component.async_register_entity_service( - SERVICE_TURN_ON, ENTITY_SERVICE_SCHEMA, "async_turn_on", [SUPPORT_TURN_ON] + SERVICE_TURN_ON, {}, "async_turn_on", [SUPPORT_TURN_ON] ) component.async_register_entity_service( - SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off", [SUPPORT_TURN_OFF] + SERVICE_TURN_OFF, {}, "async_turn_off", [SUPPORT_TURN_OFF] ) component.async_register_entity_service( - SERVICE_TOGGLE, - ENTITY_SERVICE_SCHEMA, - "async_toggle", - [SUPPORT_TURN_OFF | SUPPORT_TURN_ON], + SERVICE_TOGGLE, {}, "async_toggle", [SUPPORT_TURN_OFF | SUPPORT_TURN_ON], ) component.async_register_entity_service( SERVICE_VOLUME_UP, - ENTITY_SERVICE_SCHEMA, + {}, "async_volume_up", [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], ) component.async_register_entity_service( SERVICE_VOLUME_DOWN, - ENTITY_SERVICE_SCHEMA, + {}, "async_volume_down", [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], ) component.async_register_entity_service( SERVICE_MEDIA_PLAY_PAUSE, - ENTITY_SERVICE_SCHEMA, + {}, "async_media_play_pause", [SUPPORT_PLAY | SUPPORT_PAUSE], ) component.async_register_entity_service( - SERVICE_MEDIA_PLAY, ENTITY_SERVICE_SCHEMA, "async_media_play", [SUPPORT_PLAY] + SERVICE_MEDIA_PLAY, {}, "async_media_play", [SUPPORT_PLAY] ) component.async_register_entity_service( - SERVICE_MEDIA_PAUSE, ENTITY_SERVICE_SCHEMA, "async_media_pause", [SUPPORT_PAUSE] + SERVICE_MEDIA_PAUSE, {}, "async_media_pause", [SUPPORT_PAUSE] ) component.async_register_entity_service( - SERVICE_MEDIA_STOP, ENTITY_SERVICE_SCHEMA, "async_media_stop", [SUPPORT_STOP] + SERVICE_MEDIA_STOP, {}, "async_media_stop", [SUPPORT_STOP] ) component.async_register_entity_service( - SERVICE_MEDIA_NEXT_TRACK, - ENTITY_SERVICE_SCHEMA, - "async_media_next_track", - [SUPPORT_NEXT_TRACK], + SERVICE_MEDIA_NEXT_TRACK, {}, "async_media_next_track", [SUPPORT_NEXT_TRACK], ) component.async_register_entity_service( SERVICE_MEDIA_PREVIOUS_TRACK, - ENTITY_SERVICE_SCHEMA, + {}, "async_media_previous_track", [SUPPORT_PREVIOUS_TRACK], ) component.async_register_entity_service( - SERVICE_CLEAR_PLAYLIST, - ENTITY_SERVICE_SCHEMA, - "async_clear_playlist", - [SUPPORT_CLEAR_PLAYLIST], + SERVICE_CLEAR_PLAYLIST, {}, "async_clear_playlist", [SUPPORT_CLEAR_PLAYLIST], ) component.async_register_entity_service( SERVICE_VOLUME_SET, - MEDIA_PLAYER_SET_VOLUME_SCHEMA, + {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float}, lambda entity, call: entity.async_set_volume_level( volume=call.data[ATTR_MEDIA_VOLUME_LEVEL] ), @@ -289,7 +249,7 @@ async def async_setup(hass, config): ) component.async_register_entity_service( SERVICE_VOLUME_MUTE, - MEDIA_PLAYER_MUTE_VOLUME_SCHEMA, + {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean}, lambda entity, call: entity.async_mute_volume( mute=call.data[ATTR_MEDIA_VOLUME_MUTED] ), @@ -297,7 +257,11 @@ async def async_setup(hass, config): ) component.async_register_entity_service( SERVICE_MEDIA_SEEK, - MEDIA_PLAYER_MEDIA_SEEK_SCHEMA, + { + vol.Required(ATTR_MEDIA_SEEK_POSITION): vol.All( + vol.Coerce(float), vol.Range(min=0) + ) + }, lambda entity, call: entity.async_media_seek( position=call.data[ATTR_MEDIA_SEEK_POSITION] ), @@ -305,13 +269,13 @@ async def async_setup(hass, config): ) component.async_register_entity_service( SERVICE_SELECT_SOURCE, - MEDIA_PLAYER_SELECT_SOURCE_SCHEMA, + {vol.Required(ATTR_INPUT_SOURCE): cv.string}, "async_select_source", [SUPPORT_SELECT_SOURCE], ) component.async_register_entity_service( SERVICE_SELECT_SOUND_MODE, - MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA, + {vol.Required(ATTR_SOUND_MODE): cv.string}, "async_select_sound_mode", [SUPPORT_SELECT_SOUND_MODE], ) @@ -327,7 +291,7 @@ async def async_setup(hass, config): ) component.async_register_entity_service( SERVICE_SHUFFLE_SET, - MEDIA_PLAYER_SET_SHUFFLE_SCHEMA, + {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean}, "async_set_shuffle", [SUPPORT_SHUFFLE_SET], ) diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index 71059b98f35..af653165ee3 100644 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -17,7 +17,7 @@ from homeassistant.const import ( ) from homeassistant.components import group from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, + make_entity_service_schema, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -56,29 +56,10 @@ DEFAULT_HOLD_SECS = 0 SUPPORT_LEARN_COMMAND = 1 -REMOTE_SERVICE_ACTIVITY_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +REMOTE_SERVICE_ACTIVITY_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_ACTIVITY): cv.string} ) -REMOTE_SERVICE_SEND_COMMAND_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Required(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), - vol.Optional(ATTR_DEVICE): cv.string, - vol.Optional(ATTR_NUM_REPEATS, default=DEFAULT_NUM_REPEATS): cv.positive_int, - vol.Optional(ATTR_DELAY_SECS): vol.Coerce(float), - vol.Optional(ATTR_HOLD_SECS, default=DEFAULT_HOLD_SECS): vol.Coerce(float), - } -) - -REMOTE_SERVICE_LEARN_COMMAND_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Optional(ATTR_DEVICE): cv.string, - vol.Optional(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), - vol.Optional(ATTR_ALTERNATIVE): cv.boolean, - vol.Optional(ATTR_TIMEOUT): cv.positive_int, - } -) - @bind_hass def is_on(hass, entity_id=None): @@ -107,12 +88,27 @@ async def async_setup(hass, config): ) component.async_register_entity_service( - SERVICE_SEND_COMMAND, REMOTE_SERVICE_SEND_COMMAND_SCHEMA, "async_send_command" + SERVICE_SEND_COMMAND, + { + vol.Required(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(ATTR_DEVICE): cv.string, + vol.Optional( + ATTR_NUM_REPEATS, default=DEFAULT_NUM_REPEATS + ): cv.positive_int, + vol.Optional(ATTR_DELAY_SECS): vol.Coerce(float), + vol.Optional(ATTR_HOLD_SECS, default=DEFAULT_HOLD_SECS): vol.Coerce(float), + }, + "async_send_command", ) component.async_register_entity_service( SERVICE_LEARN_COMMAND, - REMOTE_SERVICE_LEARN_COMMAND_SCHEMA, + { + vol.Optional(ATTR_DEVICE): cv.string, + vol.Optional(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(ATTR_ALTERNATIVE): cv.boolean, + vol.Optional(ATTR_TIMEOUT): cv.positive_int, + }, "async_learn_command", ) diff --git a/homeassistant/components/script/__init__.py b/homeassistant/components/script/__init__.py index 9659cc625c0..cb9cb5194ba 100644 --- a/homeassistant/components/script/__init__.py +++ b/homeassistant/components/script/__init__.py @@ -19,7 +19,7 @@ from homeassistant.loader import bind_hass from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.service import async_set_service_schema from homeassistant.helpers.script import Script @@ -60,7 +60,7 @@ CONFIG_SCHEMA = vol.Schema( ) SCRIPT_SERVICE_SCHEMA = vol.Schema(dict) -SCRIPT_TURN_ONOFF_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +SCRIPT_TURN_ONOFF_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_VARIABLES): dict} ) RELOAD_SERVICE_SCHEMA = vol.Schema({}) diff --git a/homeassistant/components/timer/__init__.py b/homeassistant/components/timer/__init__.py index c6cc0a8c3c9..de60752eada 100644 --- a/homeassistant/components/timer/__init__.py +++ b/homeassistant/components/timer/__init__.py @@ -6,7 +6,6 @@ import voluptuous as vol from homeassistant.const import CONF_ICON, CONF_NAME import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.restore_state import RestoreEntity @@ -37,10 +36,6 @@ SERVICE_PAUSE = "pause" SERVICE_CANCEL = "cancel" SERVICE_FINISH = "finish" -SERVICE_SCHEMA_DURATION = ENTITY_SERVICE_SCHEMA.extend( - {vol.Optional(ATTR_DURATION, default=timedelta(DEFAULT_DURATION)): cv.time_period} -) - CONFIG_SCHEMA = vol.Schema( { DOMAIN: cv.schema_with_slug_keys( @@ -80,17 +75,17 @@ async def async_setup(hass, config): return False component.async_register_entity_service( - SERVICE_START, SERVICE_SCHEMA_DURATION, "async_start" - ) - component.async_register_entity_service( - SERVICE_PAUSE, ENTITY_SERVICE_SCHEMA, "async_pause" - ) - component.async_register_entity_service( - SERVICE_CANCEL, ENTITY_SERVICE_SCHEMA, "async_cancel" - ) - component.async_register_entity_service( - SERVICE_FINISH, ENTITY_SERVICE_SCHEMA, "async_finish" + SERVICE_START, + { + vol.Optional( + ATTR_DURATION, default=timedelta(DEFAULT_DURATION) + ): cv.time_period + }, + "async_start", ) + component.async_register_entity_service(SERVICE_PAUSE, {}, "async_pause") + component.async_register_entity_service(SERVICE_CANCEL, {}, "async_cancel") + component.async_register_entity_service(SERVICE_FINISH, {}, "async_finish") await component.async_add_entities(entities) return True diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py index 17eacc326d3..04e472a7828 100644 --- a/homeassistant/components/utility_meter/__init__.py +++ b/homeassistant/components/utility_meter/__init__.py @@ -7,7 +7,6 @@ import voluptuous as vol from homeassistant.const import CONF_NAME import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity @@ -39,11 +38,8 @@ ATTR_TARIFFS = "tariffs" DEFAULT_OFFSET = timedelta(hours=0) -SERVICE_SELECT_TARIFF_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_TARIFF): cv.string} -) -METER_CONFIG_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +METER_CONFIG_SCHEMA = vol.Schema( { vol.Required(CONF_SOURCE_SENSOR): cv.entity_id, vol.Optional(CONF_NAME): cv.string, @@ -110,16 +106,16 @@ async def async_setup(hass, config): register_services = True if register_services: + component.async_register_entity_service(SERVICE_RESET, {}, "async_reset_meters") + component.async_register_entity_service( - SERVICE_RESET, ENTITY_SERVICE_SCHEMA, "async_reset_meters" + SERVICE_SELECT_TARIFF, + {vol.Required(ATTR_TARIFF): cv.string}, + "async_select_tariff", ) component.async_register_entity_service( - SERVICE_SELECT_TARIFF, SERVICE_SELECT_TARIFF_SCHEMA, "async_select_tariff" - ) - - component.async_register_entity_service( - SERVICE_SELECT_NEXT_TARIFF, ENTITY_SERVICE_SCHEMA, "async_next_tariff" + SERVICE_SELECT_NEXT_TARIFF, {}, "async_next_tariff" ) return True diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index c1f1131a52f..85b3d665e17 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -19,7 +19,7 @@ from homeassistant.const import ( # noqa: F401 # STATE_PAUSED/IDLE are API from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import ( # noqa: F401 - ENTITY_SERVICE_SCHEMA, + make_entity_service_schema, PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) @@ -55,16 +55,6 @@ SERVICE_START = "start" SERVICE_PAUSE = "pause" SERVICE_STOP = "stop" -VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {vol.Required(ATTR_FAN_SPEED): cv.string} -) - -VACUUM_SEND_COMMAND_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - { - vol.Required(ATTR_COMMAND): cv.string, - vol.Optional(ATTR_PARAMS): vol.Any(dict, cv.ensure_list), - } -) STATE_CLEANING = "cleaning" STATE_DOCKED = "docked" @@ -106,43 +96,32 @@ async def async_setup(hass, config): await component.async_setup(config) + component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on") + component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") + component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") component.async_register_entity_service( - SERVICE_TURN_ON, ENTITY_SERVICE_SCHEMA, "async_turn_on" + SERVICE_START_PAUSE, {}, "async_start_pause" ) + component.async_register_entity_service(SERVICE_START, {}, "async_start") + component.async_register_entity_service(SERVICE_PAUSE, {}, "async_pause") component.async_register_entity_service( - SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off" - ) - component.async_register_entity_service( - SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle" - ) - component.async_register_entity_service( - SERVICE_START_PAUSE, ENTITY_SERVICE_SCHEMA, "async_start_pause" - ) - component.async_register_entity_service( - SERVICE_START, ENTITY_SERVICE_SCHEMA, "async_start" - ) - component.async_register_entity_service( - SERVICE_PAUSE, ENTITY_SERVICE_SCHEMA, "async_pause" - ) - component.async_register_entity_service( - SERVICE_RETURN_TO_BASE, ENTITY_SERVICE_SCHEMA, "async_return_to_base" - ) - component.async_register_entity_service( - SERVICE_CLEAN_SPOT, ENTITY_SERVICE_SCHEMA, "async_clean_spot" - ) - component.async_register_entity_service( - SERVICE_LOCATE, ENTITY_SERVICE_SCHEMA, "async_locate" - ) - component.async_register_entity_service( - SERVICE_STOP, ENTITY_SERVICE_SCHEMA, "async_stop" + SERVICE_RETURN_TO_BASE, {}, "async_return_to_base" ) + component.async_register_entity_service(SERVICE_CLEAN_SPOT, {}, "async_clean_spot") + component.async_register_entity_service(SERVICE_LOCATE, {}, "async_locate") + component.async_register_entity_service(SERVICE_STOP, {}, "async_stop") component.async_register_entity_service( SERVICE_SET_FAN_SPEED, - VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA, + {vol.Required(ATTR_FAN_SPEED): cv.string}, "async_set_fan_speed", ) component.async_register_entity_service( - SERVICE_SEND_COMMAND, VACUUM_SEND_COMMAND_SERVICE_SCHEMA, "async_send_command" + SERVICE_SEND_COMMAND, + { + vol.Required(ATTR_COMMAND): cv.string, + vol.Optional(ATTR_PARAMS): vol.Any(dict, cv.ensure_list), + }, + "async_send_command", ) return True diff --git a/homeassistant/components/wink/__init__.py b/homeassistant/components/wink/__init__.py index e2eb98938bb..3bda8b314f2 100644 --- a/homeassistant/components/wink/__init__.py +++ b/homeassistant/components/wink/__init__.py @@ -25,7 +25,7 @@ from homeassistant.const import ( from homeassistant.core import callback from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.event import track_time_interval @@ -131,11 +131,11 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -RENAME_DEVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +RENAME_DEVICE_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_NAME): cv.string}, extra=vol.ALLOW_EXTRA ) -DELETE_DEVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA) +DELETE_DEVICE_SCHEMA = make_entity_service_schema({}, extra=vol.ALLOW_EXTRA) SET_PAIRING_MODE_SCHEMA = vol.Schema( { @@ -146,31 +146,31 @@ SET_PAIRING_MODE_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -SET_VOLUME_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +SET_VOLUME_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_VOLUME): vol.In(VOLUMES)} ) -SET_SIREN_TONE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +SET_SIREN_TONE_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_TONE): vol.In(TONES)} ) -SET_CHIME_MODE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +SET_CHIME_MODE_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_TONE): vol.In(CHIME_TONES)} ) -SET_AUTO_SHUTOFF_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +SET_AUTO_SHUTOFF_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_AUTO_SHUTOFF): vol.In(AUTO_SHUTOFF_TIMES)} ) -SET_STROBE_ENABLED_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +SET_STROBE_ENABLED_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_ENABLED): cv.boolean} ) -ENABLED_SIREN_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +ENABLED_SIREN_SCHEMA = make_entity_service_schema( {vol.Required(ATTR_ENABLED): cv.boolean} ) -DIAL_CONFIG_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +DIAL_CONFIG_SCHEMA = make_entity_service_schema( { vol.Optional(ATTR_MIN_VALUE): vol.Coerce(int), vol.Optional(ATTR_MAX_VALUE): vol.Coerce(int), @@ -182,7 +182,7 @@ DIAL_CONFIG_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( } ) -DIAL_STATE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( +DIAL_STATE_SCHEMA = make_entity_service_schema( { vol.Required(ATTR_VALUE): vol.Coerce(int), vol.Optional(ATTR_LABELS): cv.ensure_list(cv.string), diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 7ca5a7e86f9..c34b104e0f7 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -715,12 +715,23 @@ PLATFORM_SCHEMA = vol.Schema( PLATFORM_SCHEMA_BASE = PLATFORM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA) -ENTITY_SERVICE_SCHEMA = vol.Schema( - { - vol.Optional(ATTR_ENTITY_ID): comp_entity_ids, - vol.Optional(ATTR_AREA_ID): vol.All(ensure_list, [str]), - } -) + +def make_entity_service_schema( + schema: dict, *, extra: int = vol.PREVENT_EXTRA +) -> vol.All: + """Create an entity service schema.""" + return vol.All( + vol.Schema( + { + **schema, + vol.Optional(ATTR_ENTITY_ID): comp_entity_ids, + vol.Optional(ATTR_AREA_ID): vol.All(ensure_list, [str]), + }, + extra=extra, + ), + has_at_least_one_key(ATTR_ENTITY_ID, ATTR_AREA_ID), + ) + EVENT_SCHEMA = vol.Schema( { diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 42b19da889e..63d1b21fc9a 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -15,7 +15,7 @@ from homeassistant.const import ( from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_per_platform, discovery -from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.service import async_extract_entity_ids from homeassistant.loader import bind_hass, async_get_integration from homeassistant.util import slugify @@ -173,24 +173,16 @@ class EntityComponent: async def async_extract_from_service(self, service, expand_group=True): """Extract all known and available entities from a service call. - Will return all entities if no entities specified in call. Will return an empty list if entities specified but unknown. This method must be run in the event loop. """ data_ent_id = service.data.get(ATTR_ENTITY_ID) - if data_ent_id in (None, ENTITY_MATCH_ALL): - if data_ent_id is None: - self.logger.warning( - "Not passing an entity ID to a service to target all " - "entities is deprecated. Update your call to %s.%s to be " - "instead: entity_id: %s", - service.domain, - service.service, - ENTITY_MATCH_ALL, - ) + if data_ent_id is None: + return [] + if data_ent_id == ENTITY_MATCH_ALL: return [entity for entity in self.entities if entity.available] entity_ids = await async_extract_entity_ids(self.hass, service, expand_group) @@ -204,7 +196,7 @@ class EntityComponent: def async_register_entity_service(self, name, schema, func, required_features=None): """Register an entity service.""" if isinstance(schema, dict): - schema = ENTITY_SERVICE_SCHEMA.extend(schema) + schema = make_entity_service_schema(schema) async def handle_service(call): """Handle the service.""" diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index e177c86c65c..45393dc0486 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -260,19 +260,7 @@ async def entity_service_call( else: entity_perms = None - # Are we trying to target all entities - if ATTR_ENTITY_ID in call.data: - target_all_entities = call.data[ATTR_ENTITY_ID] == ENTITY_MATCH_ALL - else: - # Remove the service_name parameter along with this warning - _LOGGER.warning( - "Not passing an entity ID to a service to target all " - "entities is deprecated. Update your call to %s to be " - "instead: entity_id: %s", - service_name, - ENTITY_MATCH_ALL, - ) - target_all_entities = True + target_all_entities = call.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL if not target_all_entities: # A set of entities we're trying to target. diff --git a/tests/components/alarm_control_panel/common.py b/tests/components/alarm_control_panel/common.py index 216f226ef14..d06939dce9b 100644 --- a/tests/components/alarm_control_panel/common.py +++ b/tests/components/alarm_control_panel/common.py @@ -13,11 +13,12 @@ from homeassistant.const import ( SERVICE_ALARM_ARM_AWAY, SERVICE_ALARM_ARM_NIGHT, SERVICE_ALARM_ARM_CUSTOM_BYPASS, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass -async def async_alarm_disarm(hass, code=None, entity_id=None): +async def async_alarm_disarm(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -29,7 +30,7 @@ async def async_alarm_disarm(hass, code=None, entity_id=None): @bind_hass -def alarm_disarm(hass, code=None, entity_id=None): +def alarm_disarm(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -40,7 +41,7 @@ def alarm_disarm(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data) -async def async_alarm_arm_home(hass, code=None, entity_id=None): +async def async_alarm_arm_home(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -52,7 +53,7 @@ async def async_alarm_arm_home(hass, code=None, entity_id=None): @bind_hass -def alarm_arm_home(hass, code=None, entity_id=None): +def alarm_arm_home(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for arm home.""" data = {} if code: @@ -63,7 +64,7 @@ def alarm_arm_home(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_HOME, data) -async def async_alarm_arm_away(hass, code=None, entity_id=None): +async def async_alarm_arm_away(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -75,7 +76,7 @@ async def async_alarm_arm_away(hass, code=None, entity_id=None): @bind_hass -def alarm_arm_away(hass, code=None, entity_id=None): +def alarm_arm_away(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for arm away.""" data = {} if code: @@ -86,7 +87,7 @@ def alarm_arm_away(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data) -async def async_alarm_arm_night(hass, code=None, entity_id=None): +async def async_alarm_arm_night(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -98,7 +99,7 @@ async def async_alarm_arm_night(hass, code=None, entity_id=None): @bind_hass -def alarm_arm_night(hass, code=None, entity_id=None): +def alarm_arm_night(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for arm night.""" data = {} if code: @@ -109,7 +110,7 @@ def alarm_arm_night(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_NIGHT, data) -async def async_alarm_trigger(hass, code=None, entity_id=None): +async def async_alarm_trigger(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -121,7 +122,7 @@ async def async_alarm_trigger(hass, code=None, entity_id=None): @bind_hass -def alarm_trigger(hass, code=None, entity_id=None): +def alarm_trigger(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for trigger.""" data = {} if code: @@ -132,7 +133,7 @@ def alarm_trigger(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data) -async def async_alarm_arm_custom_bypass(hass, code=None, entity_id=None): +async def async_alarm_arm_custom_bypass(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for disarm.""" data = {} if code: @@ -146,7 +147,7 @@ async def async_alarm_arm_custom_bypass(hass, code=None, entity_id=None): @bind_hass -def alarm_arm_custom_bypass(hass, code=None, entity_id=None): +def alarm_arm_custom_bypass(hass, code=None, entity_id=ENTITY_MATCH_ALL): """Send the alarm the command for arm custom bypass.""" data = {} if code: diff --git a/tests/components/automation/common.py b/tests/components/automation/common.py index 6fadbd14199..c7aa8f1eced 100644 --- a/tests/components/automation/common.py +++ b/tests/components/automation/common.py @@ -10,33 +10,34 @@ from homeassistant.const import ( SERVICE_TURN_OFF, SERVICE_TOGGLE, SERVICE_RELOAD, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass @bind_hass -async def async_turn_on(hass, entity_id=None): +async def async_turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn on specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data) @bind_hass -async def async_turn_off(hass, entity_id=None): +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn off specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data) @bind_hass -async def async_toggle(hass, entity_id=None): +async def async_toggle(hass, entity_id=ENTITY_MATCH_ALL): """Toggle specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data) @bind_hass -async def async_trigger(hass, entity_id=None): +async def async_trigger(hass, entity_id=ENTITY_MATCH_ALL): """Trigger specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} await hass.services.async_call(DOMAIN, SERVICE_TRIGGER, data) diff --git a/tests/components/camera/common.py b/tests/components/camera/common.py index 9d5d2dcd6fd..971d723d2d5 100644 --- a/tests/components/camera/common.py +++ b/tests/components/camera/common.py @@ -13,20 +13,25 @@ from homeassistant.components.camera.const import ( DATA_CAMERA_PREFS, PREF_PRELOAD_STREAM, ) -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + ENTITY_MATCH_ALL, +) from homeassistant.core import callback from homeassistant.loader import bind_hass @bind_hass -async def async_turn_off(hass, entity_id=None): +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn off camera.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data) @bind_hass -async def async_turn_on(hass, entity_id=None): +async def async_turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn on camera, and set operation mode.""" data = {} if entity_id is not None: @@ -36,7 +41,7 @@ async def async_turn_on(hass, entity_id=None): @bind_hass -def enable_motion_detection(hass, entity_id=None): +def enable_motion_detection(hass, entity_id=ENTITY_MATCH_ALL): """Enable Motion Detection.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_ENABLE_MOTION, data)) @@ -44,7 +49,7 @@ def enable_motion_detection(hass, entity_id=None): @bind_hass @callback -def async_snapshot(hass, filename, entity_id=None): +def async_snapshot(hass, filename, entity_id=ENTITY_MATCH_ALL): """Make a snapshot from a camera.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data[ATTR_FILENAME] = filename diff --git a/tests/components/climate/common.py b/tests/components/climate/common.py index 9f1ef8b084a..a5ea182f2b6 100644 --- a/tests/components/climate/common.py +++ b/tests/components/climate/common.py @@ -27,11 +27,12 @@ from homeassistant.const import ( ATTR_TEMPERATURE, SERVICE_TURN_OFF, SERVICE_TURN_ON, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass -async def async_set_preset_mode(hass, preset_mode, entity_id=None): +async def async_set_preset_mode(hass, preset_mode, entity_id=ENTITY_MATCH_ALL): """Set new preset mode.""" data = {ATTR_PRESET_MODE: preset_mode} @@ -42,7 +43,7 @@ async def async_set_preset_mode(hass, preset_mode, entity_id=None): @bind_hass -def set_preset_mode(hass, preset_mode, entity_id=None): +def set_preset_mode(hass, preset_mode, entity_id=ENTITY_MATCH_ALL): """Set new preset mode.""" data = {ATTR_PRESET_MODE: preset_mode} @@ -52,7 +53,7 @@ def set_preset_mode(hass, preset_mode, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_PRESET_MODE, data) -async def async_set_aux_heat(hass, aux_heat, entity_id=None): +async def async_set_aux_heat(hass, aux_heat, entity_id=ENTITY_MATCH_ALL): """Turn all or specified climate devices auxiliary heater on.""" data = {ATTR_AUX_HEAT: aux_heat} @@ -63,7 +64,7 @@ async def async_set_aux_heat(hass, aux_heat, entity_id=None): @bind_hass -def set_aux_heat(hass, aux_heat, entity_id=None): +def set_aux_heat(hass, aux_heat, entity_id=ENTITY_MATCH_ALL): """Turn all or specified climate devices auxiliary heater on.""" data = {ATTR_AUX_HEAT: aux_heat} @@ -76,7 +77,7 @@ def set_aux_heat(hass, aux_heat, entity_id=None): async def async_set_temperature( hass, temperature=None, - entity_id=None, + entity_id=ENTITY_MATCH_ALL, target_temp_high=None, target_temp_low=None, hvac_mode=None, @@ -103,7 +104,7 @@ async def async_set_temperature( def set_temperature( hass, temperature=None, - entity_id=None, + entity_id=ENTITY_MATCH_ALL, target_temp_high=None, target_temp_low=None, hvac_mode=None, @@ -124,7 +125,7 @@ def set_temperature( hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, kwargs) -async def async_set_humidity(hass, humidity, entity_id=None): +async def async_set_humidity(hass, humidity, entity_id=ENTITY_MATCH_ALL): """Set new target humidity.""" data = {ATTR_HUMIDITY: humidity} @@ -135,7 +136,7 @@ async def async_set_humidity(hass, humidity, entity_id=None): @bind_hass -def set_humidity(hass, humidity, entity_id=None): +def set_humidity(hass, humidity, entity_id=ENTITY_MATCH_ALL): """Set new target humidity.""" data = {ATTR_HUMIDITY: humidity} @@ -145,7 +146,7 @@ def set_humidity(hass, humidity, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_HUMIDITY, data) -async def async_set_fan_mode(hass, fan, entity_id=None): +async def async_set_fan_mode(hass, fan, entity_id=ENTITY_MATCH_ALL): """Set all or specified climate devices fan mode on.""" data = {ATTR_FAN_MODE: fan} @@ -156,7 +157,7 @@ async def async_set_fan_mode(hass, fan, entity_id=None): @bind_hass -def set_fan_mode(hass, fan, entity_id=None): +def set_fan_mode(hass, fan, entity_id=ENTITY_MATCH_ALL): """Set all or specified climate devices fan mode on.""" data = {ATTR_FAN_MODE: fan} @@ -166,7 +167,7 @@ def set_fan_mode(hass, fan, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_FAN_MODE, data) -async def async_set_hvac_mode(hass, hvac_mode, entity_id=None): +async def async_set_hvac_mode(hass, hvac_mode, entity_id=ENTITY_MATCH_ALL): """Set new target operation mode.""" data = {ATTR_HVAC_MODE: hvac_mode} @@ -177,7 +178,7 @@ async def async_set_hvac_mode(hass, hvac_mode, entity_id=None): @bind_hass -def set_operation_mode(hass, hvac_mode, entity_id=None): +def set_operation_mode(hass, hvac_mode, entity_id=ENTITY_MATCH_ALL): """Set new target operation mode.""" data = {ATTR_HVAC_MODE: hvac_mode} @@ -187,7 +188,7 @@ def set_operation_mode(hass, hvac_mode, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_HVAC_MODE, data) -async def async_set_swing_mode(hass, swing_mode, entity_id=None): +async def async_set_swing_mode(hass, swing_mode, entity_id=ENTITY_MATCH_ALL): """Set new target swing mode.""" data = {ATTR_SWING_MODE: swing_mode} @@ -198,7 +199,7 @@ async def async_set_swing_mode(hass, swing_mode, entity_id=None): @bind_hass -def set_swing_mode(hass, swing_mode, entity_id=None): +def set_swing_mode(hass, swing_mode, entity_id=ENTITY_MATCH_ALL): """Set new target swing mode.""" data = {ATTR_SWING_MODE: swing_mode} @@ -208,7 +209,7 @@ def set_swing_mode(hass, swing_mode, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_SWING_MODE, data) -async def async_turn_on(hass, entity_id=None): +async def async_turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn on device.""" data = {} @@ -218,7 +219,7 @@ async def async_turn_on(hass, entity_id=None): await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True) -async def async_turn_off(hass, entity_id=None): +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn off device.""" data = {} diff --git a/tests/components/demo/test_light.py b/tests/components/demo/test_light.py index 10b407688af..34b340b600a 100644 --- a/tests/components/demo/test_light.py +++ b/tests/components/demo/test_light.py @@ -62,10 +62,14 @@ async def test_turn_off(hass): async def test_turn_off_without_entity_id(hass): """Test light turn off all lights.""" - await hass.services.async_call("light", "turn_on", {}, blocking=True) + await hass.services.async_call( + "light", "turn_on", {"entity_id": "all"}, blocking=True + ) assert light.is_on(hass, ENTITY_LIGHT) - await hass.services.async_call("light", "turn_off", {}, blocking=True) + await hass.services.async_call( + "light", "turn_off", {"entity_id": "all"}, blocking=True + ) assert not light.is_on(hass, ENTITY_LIGHT) diff --git a/tests/components/fan/common.py b/tests/components/fan/common.py index 24a6868a372..de645dac42e 100644 --- a/tests/components/fan/common.py +++ b/tests/components/fan/common.py @@ -12,10 +12,15 @@ from homeassistant.components.fan import ( SERVICE_SET_DIRECTION, SERVICE_SET_SPEED, ) -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_ON, + SERVICE_TURN_OFF, + ENTITY_MATCH_ALL, +) -async def async_turn_on(hass, entity_id: str = None, speed: str = None) -> None: +async def async_turn_on(hass, entity_id=ENTITY_MATCH_ALL, speed: str = None) -> None: """Turn all or specified fan on.""" data = { key: value @@ -26,7 +31,7 @@ async def async_turn_on(hass, entity_id: str = None, speed: str = None) -> None: await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True) -async def async_turn_off(hass, entity_id: str = None) -> None: +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL) -> None: """Turn all or specified fan off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} @@ -34,7 +39,7 @@ async def async_turn_off(hass, entity_id: str = None) -> None: async def async_oscillate( - hass, entity_id: str = None, should_oscillate: bool = True + hass, entity_id=ENTITY_MATCH_ALL, should_oscillate: bool = True ) -> None: """Set oscillation on all or specified fan.""" data = { @@ -49,7 +54,7 @@ async def async_oscillate( await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, data, blocking=True) -async def async_set_speed(hass, entity_id: str = None, speed: str = None) -> None: +async def async_set_speed(hass, entity_id=ENTITY_MATCH_ALL, speed: str = None) -> None: """Set speed for all or specified fan.""" data = { key: value @@ -61,7 +66,7 @@ async def async_set_speed(hass, entity_id: str = None, speed: str = None) -> Non async def async_set_direction( - hass, entity_id: str = None, direction: str = None + hass, entity_id=ENTITY_MATCH_ALL, direction: str = None ) -> None: """Set direction for all or specified fan.""" data = { diff --git a/tests/components/image_processing/common.py b/tests/components/image_processing/common.py index b767884503d..8522353d3f2 100644 --- a/tests/components/image_processing/common.py +++ b/tests/components/image_processing/common.py @@ -4,20 +4,20 @@ All containing methods are legacy helpers that should not be used by new components. Instead call the service directly. """ from homeassistant.components.image_processing import DOMAIN, SERVICE_SCAN -from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.const import ATTR_ENTITY_ID, ENTITY_MATCH_ALL from homeassistant.core import callback from homeassistant.loader import bind_hass @bind_hass -def scan(hass, entity_id=None): +def scan(hass, entity_id=ENTITY_MATCH_ALL): """Force process of all cameras or given entity.""" hass.add_job(async_scan, hass, entity_id) @callback @bind_hass -def async_scan(hass, entity_id=None): +def async_scan(hass, entity_id=ENTITY_MATCH_ALL): """Force process of all cameras or given entity.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_SCAN, data)) diff --git a/tests/components/light/common.py b/tests/components/light/common.py index 416c02884dc..32678bf4daa 100644 --- a/tests/components/light/common.py +++ b/tests/components/light/common.py @@ -24,6 +24,7 @@ from homeassistant.const import ( SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass @@ -31,7 +32,7 @@ from homeassistant.loader import bind_hass @bind_hass def turn_on( hass, - entity_id=None, + entity_id=ENTITY_MATCH_ALL, transition=None, brightness=None, brightness_pct=None, @@ -69,7 +70,7 @@ def turn_on( async def async_turn_on( hass, - entity_id=None, + entity_id=ENTITY_MATCH_ALL, transition=None, brightness=None, brightness_pct=None, @@ -110,12 +111,12 @@ async def async_turn_on( @bind_hass -def turn_off(hass, entity_id=None, transition=None): +def turn_off(hass, entity_id=ENTITY_MATCH_ALL, transition=None): """Turn all or specified light off.""" hass.add_job(async_turn_off, hass, entity_id, transition) -async def async_turn_off(hass, entity_id=None, transition=None): +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL, transition=None): """Turn all or specified light off.""" data = { key: value @@ -127,12 +128,12 @@ async def async_turn_off(hass, entity_id=None, transition=None): @bind_hass -def toggle(hass, entity_id=None, transition=None): +def toggle(hass, entity_id=ENTITY_MATCH_ALL, transition=None): """Toggle all or specified light.""" hass.add_job(async_toggle, hass, entity_id, transition) -async def async_toggle(hass, entity_id=None, transition=None): +async def async_toggle(hass, entity_id=ENTITY_MATCH_ALL, transition=None): """Toggle all or specified light.""" data = { key: value diff --git a/tests/components/lock/common.py b/tests/components/lock/common.py index 2ad8f075bce..a658befca55 100644 --- a/tests/components/lock/common.py +++ b/tests/components/lock/common.py @@ -10,12 +10,13 @@ from homeassistant.const import ( SERVICE_LOCK, SERVICE_UNLOCK, SERVICE_OPEN, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass @bind_hass -def lock(hass, entity_id=None, code=None): +def lock(hass, entity_id=ENTITY_MATCH_ALL, code=None): """Lock all or specified locks.""" data = {} if code: @@ -26,7 +27,7 @@ def lock(hass, entity_id=None, code=None): hass.services.call(DOMAIN, SERVICE_LOCK, data) -async def async_lock(hass, entity_id=None, code=None): +async def async_lock(hass, entity_id=ENTITY_MATCH_ALL, code=None): """Lock all or specified locks.""" data = {} if code: @@ -38,7 +39,7 @@ async def async_lock(hass, entity_id=None, code=None): @bind_hass -def unlock(hass, entity_id=None, code=None): +def unlock(hass, entity_id=ENTITY_MATCH_ALL, code=None): """Unlock all or specified locks.""" data = {} if code: @@ -49,7 +50,7 @@ def unlock(hass, entity_id=None, code=None): hass.services.call(DOMAIN, SERVICE_UNLOCK, data) -async def async_unlock(hass, entity_id=None, code=None): +async def async_unlock(hass, entity_id=ENTITY_MATCH_ALL, code=None): """Lock all or specified locks.""" data = {} if code: @@ -61,7 +62,7 @@ async def async_unlock(hass, entity_id=None, code=None): @bind_hass -def open_lock(hass, entity_id=None, code=None): +def open_lock(hass, entity_id=ENTITY_MATCH_ALL, code=None): """Open all or specified locks.""" data = {} if code: @@ -72,7 +73,7 @@ def open_lock(hass, entity_id=None, code=None): hass.services.call(DOMAIN, SERVICE_OPEN, data) -async def async_open_lock(hass, entity_id=None, code=None): +async def async_open_lock(hass, entity_id=ENTITY_MATCH_ALL, code=None): """Lock all or specified locks.""" data = {} if code: diff --git a/tests/components/media_player/common.py b/tests/components/media_player/common.py index 1d1f811c91e..177f8169ff9 100644 --- a/tests/components/media_player/common.py +++ b/tests/components/media_player/common.py @@ -32,47 +32,48 @@ from homeassistant.const import ( SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass @bind_hass -def turn_on(hass, entity_id=None): +def turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn on specified media player or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TURN_ON, data) @bind_hass -def turn_off(hass, entity_id=None): +def turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn off specified media player or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) @bind_hass -def toggle(hass, entity_id=None): +def toggle(hass, entity_id=ENTITY_MATCH_ALL): """Toggle specified media player or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TOGGLE, data) @bind_hass -def volume_up(hass, entity_id=None): +def volume_up(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for volume up.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_VOLUME_UP, data) @bind_hass -def volume_down(hass, entity_id=None): +def volume_down(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for volume down.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_VOLUME_DOWN, data) @bind_hass -def mute_volume(hass, mute, entity_id=None): +def mute_volume(hass, mute, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for muting the volume.""" data = {ATTR_MEDIA_VOLUME_MUTED: mute} @@ -83,7 +84,7 @@ def mute_volume(hass, mute, entity_id=None): @bind_hass -def set_volume_level(hass, volume, entity_id=None): +def set_volume_level(hass, volume, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for setting the volume.""" data = {ATTR_MEDIA_VOLUME_LEVEL: volume} @@ -94,49 +95,49 @@ def set_volume_level(hass, volume, entity_id=None): @bind_hass -def media_play_pause(hass, entity_id=None): +def media_play_pause(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for play/pause.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, data) @bind_hass -def media_play(hass, entity_id=None): +def media_play(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for play/pause.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY, data) @bind_hass -def media_pause(hass, entity_id=None): +def media_pause(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for pause.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PAUSE, data) @bind_hass -def media_stop(hass, entity_id=None): +def media_stop(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for stop.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_STOP, data) @bind_hass -def media_next_track(hass, entity_id=None): +def media_next_track(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for next track.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_NEXT_TRACK, data) @bind_hass -def media_previous_track(hass, entity_id=None): +def media_previous_track(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for prev track.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK, data) @bind_hass -def media_seek(hass, position, entity_id=None): +def media_seek(hass, position, entity_id=ENTITY_MATCH_ALL): """Send the media player the command to seek in current playing media.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data[ATTR_MEDIA_SEEK_POSITION] = position @@ -144,7 +145,7 @@ def media_seek(hass, position, entity_id=None): @bind_hass -def play_media(hass, media_type, media_id, entity_id=None, enqueue=None): +def play_media(hass, media_type, media_id, entity_id=ENTITY_MATCH_ALL, enqueue=None): """Send the media player the command for playing media.""" data = {ATTR_MEDIA_CONTENT_TYPE: media_type, ATTR_MEDIA_CONTENT_ID: media_id} @@ -158,7 +159,7 @@ def play_media(hass, media_type, media_id, entity_id=None, enqueue=None): @bind_hass -def select_source(hass, source, entity_id=None): +def select_source(hass, source, entity_id=ENTITY_MATCH_ALL): """Send the media player the command to select input source.""" data = {ATTR_INPUT_SOURCE: source} @@ -169,7 +170,7 @@ def select_source(hass, source, entity_id=None): @bind_hass -def clear_playlist(hass, entity_id=None): +def clear_playlist(hass, entity_id=ENTITY_MATCH_ALL): """Send the media player the command for clear playlist.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_CLEAR_PLAYLIST, data) diff --git a/tests/components/mqtt/test_state_vacuum.py b/tests/components/mqtt/test_state_vacuum.py index 572c3b05752..7919e07767d 100644 --- a/tests/components/mqtt/test_state_vacuum.py +++ b/tests/components/mqtt/test_state_vacuum.py @@ -28,6 +28,7 @@ from homeassistant.const import ( CONF_PLATFORM, STATE_UNAVAILABLE, STATE_UNKNOWN, + ENTITY_MATCH_ALL, ) from homeassistant.setup import async_setup_component @@ -75,29 +76,41 @@ async def test_all_commands(hass, mqtt_mock): assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.services.async_call(DOMAIN, SERVICE_START, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_START, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_called_once_with(COMMAND_TOPIC, "start", 0, False) mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_STOP, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_STOP, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_called_once_with(COMMAND_TOPIC, "stop", 0, False) mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_PAUSE, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_PAUSE, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_called_once_with(COMMAND_TOPIC, "pause", 0, False) mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_LOCATE, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_LOCATE, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_called_once_with(COMMAND_TOPIC, "locate", 0, False) mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_CLEAN_SPOT, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_CLEAN_SPOT, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_called_once_with( COMMAND_TOPIC, "clean_spot", 0, False ) mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_RETURN_TO_BASE, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_RETURN_TO_BASE, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_called_once_with( COMMAND_TOPIC, "return_to_base", 0, False ) @@ -134,27 +147,39 @@ async def test_commands_without_supported_features(hass, mqtt_mock): assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config}) - await hass.services.async_call(DOMAIN, SERVICE_START, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_START, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_PAUSE, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_PAUSE, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_STOP, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_STOP, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_RETURN_TO_BASE, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_RETURN_TO_BASE, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_LOCATE, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_LOCATE, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await hass.services.async_call(DOMAIN, SERVICE_CLEAN_SPOT, blocking=True) + await hass.services.async_call( + DOMAIN, SERVICE_CLEAN_SPOT, {"entity_id": ENTITY_MATCH_ALL}, blocking=True + ) mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() diff --git a/tests/components/remote/common.py b/tests/components/remote/common.py index a35489f1780..d972640487a 100644 --- a/tests/components/remote/common.py +++ b/tests/components/remote/common.py @@ -15,12 +15,17 @@ from homeassistant.components.remote import ( SERVICE_LEARN_COMMAND, SERVICE_SEND_COMMAND, ) -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + ENTITY_MATCH_ALL, +) from homeassistant.loader import bind_hass @bind_hass -def turn_on(hass, activity=None, entity_id=None): +def turn_on(hass, activity=None, entity_id=ENTITY_MATCH_ALL): """Turn all or specified remote on.""" data = { key: value @@ -31,7 +36,7 @@ def turn_on(hass, activity=None, entity_id=None): @bind_hass -def turn_off(hass, activity=None, entity_id=None): +def turn_off(hass, activity=None, entity_id=ENTITY_MATCH_ALL): """Turn all or specified remote off.""" data = {} if activity: @@ -45,7 +50,12 @@ def turn_off(hass, activity=None, entity_id=None): @bind_hass def send_command( - hass, command, entity_id=None, device=None, num_repeats=None, delay_secs=None + hass, + command, + entity_id=ENTITY_MATCH_ALL, + device=None, + num_repeats=None, + delay_secs=None, ): """Send a command to a device.""" data = {ATTR_COMMAND: command} @@ -66,7 +76,12 @@ def send_command( @bind_hass def learn_command( - hass, entity_id=None, device=None, command=None, alternative=None, timeout=None + hass, + entity_id=ENTITY_MATCH_ALL, + device=None, + command=None, + alternative=None, + timeout=None, ): """Learn a command from a device.""" data = {} diff --git a/tests/components/scene/common.py b/tests/components/scene/common.py index 4f8123ca638..5da0cc21db0 100644 --- a/tests/components/scene/common.py +++ b/tests/components/scene/common.py @@ -4,12 +4,12 @@ All containing methods are legacy helpers that should not be used by new components. Instead call the service directly. """ from homeassistant.components.scene import DOMAIN -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON, ENTITY_MATCH_ALL from homeassistant.loader import bind_hass @bind_hass -def activate(hass, entity_id=None): +def activate(hass, entity_id=ENTITY_MATCH_ALL): """Activate a scene.""" data = {} diff --git a/tests/components/smartthings/test_climate.py b/tests/components/smartthings/test_climate.py index 630174a0661..79919a376cd 100644 --- a/tests/components/smartthings/test_climate.py +++ b/tests/components/smartthings/test_climate.py @@ -551,7 +551,9 @@ async def test_set_turn_off(hass, air_conditioner): await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner]) state = hass.states.get("climate.air_conditioner") assert state.state == HVAC_MODE_HEAT_COOL - await hass.services.async_call(CLIMATE_DOMAIN, SERVICE_TURN_OFF, blocking=True) + await hass.services.async_call( + CLIMATE_DOMAIN, SERVICE_TURN_OFF, {"entity_id": "all"}, blocking=True + ) state = hass.states.get("climate.air_conditioner") assert state.state == HVAC_MODE_OFF @@ -562,7 +564,9 @@ async def test_set_turn_on(hass, air_conditioner): await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner]) state = hass.states.get("climate.air_conditioner") assert state.state == HVAC_MODE_OFF - await hass.services.async_call(CLIMATE_DOMAIN, SERVICE_TURN_ON, blocking=True) + await hass.services.async_call( + CLIMATE_DOMAIN, SERVICE_TURN_ON, {"entity_id": "all"}, blocking=True + ) state = hass.states.get("climate.air_conditioner") assert state.state == HVAC_MODE_HEAT_COOL diff --git a/tests/components/smartthings/test_cover.py b/tests/components/smartthings/test_cover.py index 19a2ec3463a..26b68c0cb1f 100644 --- a/tests/components/smartthings/test_cover.py +++ b/tests/components/smartthings/test_cover.py @@ -114,7 +114,10 @@ async def test_set_cover_position(hass, device_factory): await setup_platform(hass, COVER_DOMAIN, devices=[device]) # Act await hass.services.async_call( - COVER_DOMAIN, SERVICE_SET_COVER_POSITION, {ATTR_POSITION: 50}, blocking=True + COVER_DOMAIN, + SERVICE_SET_COVER_POSITION, + {ATTR_POSITION: 50, "entity_id": "all"}, + blocking=True, ) state = hass.states.get("cover.shade") @@ -136,7 +139,10 @@ async def test_set_cover_position_unsupported(hass, device_factory): await setup_platform(hass, COVER_DOMAIN, devices=[device]) # Act await hass.services.async_call( - COVER_DOMAIN, SERVICE_SET_COVER_POSITION, {ATTR_POSITION: 50}, blocking=True + COVER_DOMAIN, + SERVICE_SET_COVER_POSITION, + {"entity_id": "all", ATTR_POSITION: 50}, + blocking=True, ) state = hass.states.get("cover.shade") diff --git a/tests/components/switch/common.py b/tests/components/switch/common.py index 4491b07cd73..2c6b1ccd0d2 100644 --- a/tests/components/switch/common.py +++ b/tests/components/switch/common.py @@ -4,29 +4,34 @@ All containing methods are legacy helpers that should not be used by new components. Instead call the service directly. """ from homeassistant.components.switch import DOMAIN -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + ENTITY_MATCH_ALL, +) from homeassistant.loader import bind_hass @bind_hass -def turn_on(hass, entity_id=None): +def turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified switch on.""" hass.add_job(async_turn_on, hass, entity_id) -async def async_turn_on(hass, entity_id=None): +async def async_turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified switch on.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True) @bind_hass -def turn_off(hass, entity_id=None): +def turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified switch off.""" hass.add_job(async_turn_off, hass, entity_id) -async def async_turn_off(hass, entity_id=None): +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified switch off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data, blocking=True) diff --git a/tests/components/vacuum/common.py b/tests/components/vacuum/common.py index 7d9f645449f..59f600590b1 100644 --- a/tests/components/vacuum/common.py +++ b/tests/components/vacuum/common.py @@ -23,137 +23,138 @@ from homeassistant.const import ( SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, + ENTITY_MATCH_ALL, ) from homeassistant.loader import bind_hass @bind_hass -def turn_on(hass, entity_id=None): +def turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified vacuum on.""" hass.add_job(async_turn_on, hass, entity_id) -async def async_turn_on(hass, entity_id=None): +async def async_turn_on(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified vacuum on.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True) @bind_hass -def turn_off(hass, entity_id=None): +def turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified vacuum off.""" hass.add_job(async_turn_off, hass, entity_id) -async def async_turn_off(hass, entity_id=None): +async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL): """Turn all or specified vacuum off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data, blocking=True) @bind_hass -def toggle(hass, entity_id=None): +def toggle(hass, entity_id=ENTITY_MATCH_ALL): """Toggle all or specified vacuum.""" hass.add_job(async_toggle, hass, entity_id) -async def async_toggle(hass, entity_id=None): +async def async_toggle(hass, entity_id=ENTITY_MATCH_ALL): """Toggle all or specified vacuum.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data, blocking=True) @bind_hass -def locate(hass, entity_id=None): +def locate(hass, entity_id=ENTITY_MATCH_ALL): """Locate all or specified vacuum.""" hass.add_job(async_locate, hass, entity_id) -async def async_locate(hass, entity_id=None): +async def async_locate(hass, entity_id=ENTITY_MATCH_ALL): """Locate all or specified vacuum.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_LOCATE, data, blocking=True) @bind_hass -def clean_spot(hass, entity_id=None): +def clean_spot(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to perform a spot clean-up.""" hass.add_job(async_clean_spot, hass, entity_id) -async def async_clean_spot(hass, entity_id=None): +async def async_clean_spot(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to perform a spot clean-up.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_CLEAN_SPOT, data, blocking=True) @bind_hass -def return_to_base(hass, entity_id=None): +def return_to_base(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to return to base.""" hass.add_job(async_return_to_base, hass, entity_id) -async def async_return_to_base(hass, entity_id=None): +async def async_return_to_base(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to return to base.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_RETURN_TO_BASE, data, blocking=True) @bind_hass -def start_pause(hass, entity_id=None): +def start_pause(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to start or pause the current task.""" hass.add_job(async_start_pause, hass, entity_id) -async def async_start_pause(hass, entity_id=None): +async def async_start_pause(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to start or pause the current task.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_START_PAUSE, data, blocking=True) @bind_hass -def start(hass, entity_id=None): +def start(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to start or resume the current task.""" hass.add_job(async_start, hass, entity_id) -async def async_start(hass, entity_id=None): +async def async_start(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or specified vacuum to start or resume the current task.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_START, data, blocking=True) @bind_hass -def pause(hass, entity_id=None): +def pause(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or the specified vacuum to pause the current task.""" hass.add_job(async_pause, hass, entity_id) -async def async_pause(hass, entity_id=None): +async def async_pause(hass, entity_id=ENTITY_MATCH_ALL): """Tell all or the specified vacuum to pause the current task.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_PAUSE, data, blocking=True) @bind_hass -def stop(hass, entity_id=None): +def stop(hass, entity_id=ENTITY_MATCH_ALL): """Stop all or specified vacuum.""" hass.add_job(async_stop, hass, entity_id) -async def async_stop(hass, entity_id=None): +async def async_stop(hass, entity_id=ENTITY_MATCH_ALL): """Stop all or specified vacuum.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None await hass.services.async_call(DOMAIN, SERVICE_STOP, data, blocking=True) @bind_hass -def set_fan_speed(hass, fan_speed, entity_id=None): +def set_fan_speed(hass, fan_speed, entity_id=ENTITY_MATCH_ALL): """Set fan speed for all or specified vacuum.""" hass.add_job(async_set_fan_speed, hass, fan_speed, entity_id) -async def async_set_fan_speed(hass, fan_speed, entity_id=None): +async def async_set_fan_speed(hass, fan_speed, entity_id=ENTITY_MATCH_ALL): """Set fan speed for all or specified vacuum.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data[ATTR_FAN_SPEED] = fan_speed @@ -161,12 +162,12 @@ async def async_set_fan_speed(hass, fan_speed, entity_id=None): @bind_hass -def send_command(hass, command, params=None, entity_id=None): +def send_command(hass, command, params=None, entity_id=ENTITY_MATCH_ALL): """Send command to all or specified vacuum.""" hass.add_job(async_send_command, hass, command, params, entity_id) -async def async_send_command(hass, command, params=None, entity_id=None): +async def async_send_command(hass, command, params=None, entity_id=ENTITY_MATCH_ALL): """Send command to all or specified vacuum.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data[ATTR_COMMAND] = command diff --git a/tests/components/water_heater/common.py b/tests/components/water_heater/common.py index 3fb010ab55c..0808e3e3dac 100644 --- a/tests/components/water_heater/common.py +++ b/tests/components/water_heater/common.py @@ -12,12 +12,12 @@ from homeassistant.components.water_heater import ( SERVICE_SET_TEMPERATURE, SERVICE_SET_OPERATION_MODE, ) -from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE +from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, ENTITY_MATCH_ALL from homeassistant.loader import bind_hass @bind_hass -def set_away_mode(hass, away_mode, entity_id=None): +def set_away_mode(hass, away_mode, entity_id=ENTITY_MATCH_ALL): """Turn all or specified water_heater devices away mode on.""" data = {ATTR_AWAY_MODE: away_mode} @@ -28,7 +28,9 @@ def set_away_mode(hass, away_mode, entity_id=None): @bind_hass -def set_temperature(hass, temperature=None, entity_id=None, operation_mode=None): +def set_temperature( + hass, temperature=None, entity_id=ENTITY_MATCH_ALL, operation_mode=None +): """Set new target temperature.""" kwargs = { key: value @@ -44,7 +46,7 @@ def set_temperature(hass, temperature=None, entity_id=None, operation_mode=None) @bind_hass -def set_operation_mode(hass, operation_mode, entity_id=None): +def set_operation_mode(hass, operation_mode, entity_id=ENTITY_MATCH_ALL): """Set new target operation mode.""" data = {ATTR_OPERATION_MODE: operation_mode} diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index 0d52f430ff5..350aa88b6af 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -9,6 +9,7 @@ import asynctest import pytest import homeassistant.core as ha +from homeassistant.const import ENTITY_MATCH_ALL from homeassistant.exceptions import PlatformNotReady from homeassistant.components import group from homeassistant.helpers.entity_component import EntityComponent @@ -194,7 +195,7 @@ async def test_extract_from_service_available_device(hass): ] ) - call_1 = ha.ServiceCall("test", "service") + call_1 = ha.ServiceCall("test", "service", data={"entity_id": ENTITY_MATCH_ALL}) assert ["test_domain.test_1", "test_domain.test_3"] == sorted( ent.entity_id for ent in (await component.async_extract_from_service(call_1)) @@ -250,7 +251,7 @@ async def test_platform_not_ready(hass): assert "test_domain.mod1" in hass.config.components -async def test_extract_from_service_returns_all_if_no_entity_id(hass): +async def test_extract_from_service_fails_if_no_entity_id(hass): """Test the extraction of everything from service.""" component = EntityComponent(_LOGGER, DOMAIN, hass) await component.async_add_entities( @@ -259,7 +260,7 @@ async def test_extract_from_service_returns_all_if_no_entity_id(hass): call = ha.ServiceCall("test", "service") - assert ["test_domain.test_1", "test_domain.test_2"] == sorted( + assert [] == sorted( ent.entity_id for ent in (await component.async_extract_from_service(call)) ) @@ -445,12 +446,9 @@ async def test_extract_all_omit_entity_id(hass, caplog): call = ha.ServiceCall("test", "service") - assert ["test_domain.test_1", "test_domain.test_2"] == sorted( + assert [] == sorted( ent.entity_id for ent in await component.async_extract_from_service(call) ) - assert ( - "Not passing an entity ID to a service to target all entities is " "deprecated" - ) in caplog.text async def test_extract_all_use_match_all(hass, caplog): diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index de8142a6374..20be7db42f5 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -11,7 +11,7 @@ import pytest # To prevent circular import when running just this file import homeassistant.components # noqa: F401 from homeassistant import core as ha, exceptions -from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ENTITY_ID +from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ENTITY_ID, ENTITY_MATCH_ALL from homeassistant.setup import async_setup_component import homeassistant.helpers.config_validation as cv from homeassistant.auth.permissions import PolicyPermissions @@ -334,7 +334,10 @@ async def test_call_context_target_all(hass, mock_service_platform_call, mock_en [Mock(entities=mock_entities)], Mock(), ha.ServiceCall( - "test_domain", "test_service", context=ha.Context(user_id="mock-id") + "test_domain", + "test_service", + data={"entity_id": ENTITY_MATCH_ALL}, + context=ha.Context(user_id="mock-id"), ), ) @@ -407,7 +410,9 @@ async def test_call_no_context_target_all( hass, [Mock(entities=mock_entities)], Mock(), - ha.ServiceCall("test_domain", "test_service"), + ha.ServiceCall( + "test_domain", "test_service", data={"entity_id": ENTITY_MATCH_ALL} + ), ) assert len(mock_service_platform_call.mock_calls) == 1 @@ -458,9 +463,9 @@ async def test_call_with_match_all( async def test_call_with_omit_entity_id( - hass, mock_service_platform_call, mock_entities, caplog + hass, mock_service_platform_call, mock_entities ): - """Check we only target allowed entities if targetting all.""" + """Check service call if we do not pass an entity ID.""" await service.entity_service_call( hass, [Mock(entities=mock_entities)], @@ -470,13 +475,7 @@ async def test_call_with_omit_entity_id( assert len(mock_service_platform_call.mock_calls) == 1 entities = mock_service_platform_call.mock_calls[0][1][2] - assert entities == [ - mock_entities["light.kitchen"], - mock_entities["light.living_room"], - ] - assert ( - "Not passing an entity ID to a service to target " "all entities is deprecated" - ) in caplog.text + assert entities == [] async def test_register_admin_service(hass, hass_read_only_user, hass_admin_user):