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
This commit is contained in:
Paulus Schoutsen 2019-12-02 16:23:12 -08:00 committed by GitHub
parent 9587afc5ce
commit 02d9ed5e36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 538 additions and 626 deletions

View File

@ -17,7 +17,7 @@ from homeassistant.const import (
) )
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA, make_entity_service_schema,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
@ -41,9 +41,7 @@ ATTR_CODE_ARM_REQUIRED = "code_arm_required"
ENTITY_ID_FORMAT = DOMAIN + ".{}" ENTITY_ID_FORMAT = DOMAIN + ".{}"
ALARM_SERVICE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( ALARM_SERVICE_SCHEMA = make_entity_service_schema({vol.Optional(ATTR_CODE): cv.string})
{vol.Optional(ATTR_CODE): cv.string}
)
async def async_setup(hass, config): async def async_setup(hass, config):

View File

@ -24,7 +24,7 @@ from homeassistant.core import Context, CoreState, HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import condition, extract_domain_configs, script from homeassistant.helpers import condition, extract_domain_configs, script
import homeassistant.helpers.config_validation as cv 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 import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity 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} {vol.Optional(ATTR_VARIABLES, default={}): dict}
) )
@ -184,12 +184,18 @@ async def async_setup(hass, config):
) )
hass.services.async_register( 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): for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF):
hass.services.async_register( 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 return True

View File

@ -19,7 +19,7 @@ from homeassistant.const import (
) )
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA, make_entity_service_schema,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
@ -84,15 +84,12 @@ CONVERTIBLE_ATTRIBUTE = [ATTR_TEMPERATURE, ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEM
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SET_AUX_HEAT_SCHEMA = ENTITY_SERVICE_SCHEMA.extend(
{vol.Required(ATTR_AUX_HEAT): cv.boolean} SET_TEMPERATURE_SCHEMA = vol.All(
)
SET_TEMPERATURE_SCHEMA = vol.Schema(
vol.All(
cv.has_at_least_one_key( cv.has_at_least_one_key(
ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW
), ),
ENTITY_SERVICE_SCHEMA.extend( make_entity_service_schema(
{ {
vol.Exclusive(ATTR_TEMPERATURE, "temperature"): vol.Coerce(float), vol.Exclusive(ATTR_TEMPERATURE, "temperature"): vol.Coerce(float),
vol.Inclusive(ATTR_TARGET_TEMP_HIGH, "temperature"): vol.Coerce(float), vol.Inclusive(ATTR_TARGET_TEMP_HIGH, "temperature"): vol.Coerce(float),
@ -101,22 +98,6 @@ SET_TEMPERATURE_SCHEMA = vol.Schema(
} }
), ),
) )
)
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}
)
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
@ -126,32 +107,40 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
) )
await component.async_setup(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( 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( 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( 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( 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( 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( 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( component.async_register_entity_service(
SERVICE_SET_HUMIDITY, SET_HUMIDITY_SCHEMA, "async_set_humidity" SERVICE_SET_SWING_MODE,
) {vol.Required(ATTR_SWING_MODE): cv.string},
component.async_register_entity_service( "async_set_swing_mode",
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"
) )
return True return True

View File

@ -6,7 +6,6 @@ import voluptuous as vol
from homeassistant.const import CONF_ICON, CONF_NAME, CONF_MAXIMUM, CONF_MINIMUM from homeassistant.const import CONF_ICON, CONF_NAME, CONF_MAXIMUM, CONF_MINIMUM
import homeassistant.helpers.config_validation as cv 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.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
@ -33,15 +32,6 @@ SERVICE_INCREMENT = "increment"
SERVICE_RESET = "reset" SERVICE_RESET = "reset"
SERVICE_CONFIGURE = "configure" 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( CONFIG_SCHEMA = vol.Schema(
{ {
@ -95,17 +85,19 @@ async def async_setup(hass, config):
if not entities: if not entities:
return False 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( component.async_register_entity_service(
SERVICE_INCREMENT, ENTITY_SERVICE_SCHEMA, "async_increment" SERVICE_CONFIGURE,
) {
component.async_register_entity_service( vol.Optional(ATTR_MINIMUM): vol.Any(None, vol.Coerce(int)),
SERVICE_DECREMENT, ENTITY_SERVICE_SCHEMA, "async_decrement" vol.Optional(ATTR_MAXIMUM): vol.Any(None, vol.Coerce(int)),
) vol.Optional(ATTR_STEP): cv.positive_int,
component.async_register_entity_service( vol.Optional(ATTR_INITIAL): cv.positive_int,
SERVICE_RESET, ENTITY_SERVICE_SCHEMA, "async_reset" vol.Optional(VALUE): cv.positive_int,
) },
component.async_register_entity_service( "async_configure",
SERVICE_CONFIGURE, SERVICE_SCHEMA_CONFIGURE, "async_configure"
) )
await component.async_add_entities(entities) await component.async_add_entities(entities)

View File

@ -13,7 +13,6 @@ from homeassistant.helpers.config_validation import ( # noqa: F401
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
from homeassistant.components import group from homeassistant.components import group
from homeassistant.const import ( from homeassistant.const import (
SERVICE_OPEN_COVER, SERVICE_OPEN_COVER,
@ -83,18 +82,6 @@ ATTR_POSITION = "position"
ATTR_TILT_POSITION = "tilt_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 @bind_hass
def is_closed(hass, entity_id=None): def is_closed(hass, entity_id=None):
@ -111,48 +98,50 @@ async def async_setup(hass, config):
await component.async_setup(config) await component.async_setup(config)
component.async_register_entity_service( component.async_register_entity_service(SERVICE_OPEN_COVER, {}, "async_open_cover")
SERVICE_OPEN_COVER, ENTITY_SERVICE_SCHEMA, "async_open_cover"
)
component.async_register_entity_service( 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( component.async_register_entity_service(
SERVICE_SET_COVER_POSITION, 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", "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( 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( 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( component.async_register_entity_service(
SERVICE_OPEN_COVER_TILT, ENTITY_SERVICE_SCHEMA, "async_open_cover_tilt" SERVICE_STOP_COVER_TILT, {}, "async_stop_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"
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SET_COVER_TILT_POSITION, 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", "async_set_cover_tilt_position",
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_TOGGLE_COVER_TILT, ENTITY_SERVICE_SCHEMA, "async_toggle_tilt" SERVICE_TOGGLE_COVER_TILT, {}, "async_toggle_tilt"
) )
return True return True

View File

@ -12,7 +12,6 @@ from homeassistant.loader import bind_hass
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
@ -57,20 +56,6 @@ PROP_TO_ATTR = {
"current_direction": ATTR_DIRECTION, "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 @bind_hass
def is_on(hass, entity_id: Optional[str] = None) -> bool: 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) await component.async_setup(config)
component.async_register_entity_service( 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( 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( component.async_register_entity_service(
SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle" SERVICE_SET_DIRECTION,
) {vol.Optional(ATTR_DIRECTION): cv.string},
component.async_register_entity_service( "async_set_direction",
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"
) )
return True return True

View File

@ -32,7 +32,7 @@ from homeassistant.helpers.entity import Entity, async_generate_entity_id
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change
import homeassistant.helpers.config_validation as cv 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 from homeassistant.helpers.typing import HomeAssistantType
@ -63,28 +63,6 @@ SERVICE_REMOVE = "remove"
CONTROL_TYPES = vol.In(["hidden", None]) 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__) _LOGGER = logging.getLogger(__name__)
@ -227,7 +205,7 @@ async def async_setup(hass, config):
await component.async_add_entities(auto) await component.async_add_entities(auto)
hass.services.async_register( 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() service_lock = asyncio.Lock()
@ -319,11 +297,29 @@ async def async_setup(hass, config):
await component.async_remove_entity(entity_id) await component.async_remove_entity(entity_id)
hass.services.async_register( 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( 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): async def visibility_service_handler(service):
@ -344,7 +340,7 @@ async def async_setup(hass, config):
DOMAIN, DOMAIN,
SERVICE_SET_VISIBILITY, SERVICE_SET_VISIBILITY,
visibility_service_handler, visibility_service_handler,
schema=SET_VISIBILITY_SERVICE_SCHEMA, schema=make_entity_service_schema({vol.Required(ATTR_VISIBLE): cv.boolean}),
) )
return True return True

View File

@ -11,7 +11,7 @@ from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME, CONF_ENTITY_ID, CONF_
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv 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 import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.util.async_ import run_callback_threadsafe from homeassistant.util.async_ import run_callback_threadsafe
@ -124,7 +124,7 @@ async def async_setup(hass, config):
await asyncio.wait(update_tasks) await asyncio.wait(update_tasks)
hass.services.async_register( 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 return True

View File

@ -13,7 +13,6 @@ from homeassistant.const import (
) )
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
import homeassistant.helpers.config_validation as cv 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 import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
@ -68,17 +67,11 @@ async def async_setup(hass, config):
if not entities: if not entities:
return False return False
component.async_register_entity_service( component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on")
SERVICE_TURN_ON, ENTITY_SERVICE_SCHEMA, "async_turn_on"
)
component.async_register_entity_service( component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off")
SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off"
)
component.async_register_entity_service( component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle")
SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle"
)
await component.async_add_entities(entities) await component.async_add_entities(entities)
return True return True

View File

@ -6,7 +6,6 @@ import voluptuous as vol
from homeassistant.const import ATTR_DATE, ATTR_TIME, CONF_ICON, CONF_NAME from homeassistant.const import ATTR_DATE, ATTR_TIME, CONF_ICON, CONF_NAME
import homeassistant.helpers.config_validation as cv 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.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
@ -27,14 +26,6 @@ ATTR_DATETIME = "datetime"
SERVICE_SET_DATETIME = "set_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): def has_date_or_time(conf):
"""Check at least date or time is true.""" """Check at least date or time is true."""
@ -108,7 +99,13 @@ async def async_setup(hass, config):
entity.async_set_datetime(date, time) entity.async_set_datetime(date, time)
component.async_register_entity_service( 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) await component.async_add_entities(entities)

View File

@ -4,7 +4,6 @@ import logging
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
from homeassistant.const import ( from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
ATTR_MODE, ATTR_MODE,
@ -38,10 +37,6 @@ SERVICE_SET_VALUE = "set_value"
SERVICE_INCREMENT = "increment" SERVICE_INCREMENT = "increment"
SERVICE_DECREMENT = "decrement" SERVICE_DECREMENT = "decrement"
SERVICE_SET_VALUE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend(
{vol.Required(ATTR_VALUE): vol.Coerce(float)}
)
def _cv_input_number(cfg): def _cv_input_number(cfg):
"""Configure validation helper for input number (voluptuous).""" """Configure validation helper for input number (voluptuous)."""
@ -110,16 +105,14 @@ async def async_setup(hass, config):
return False return False
component.async_register_entity_service( 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( component.async_register_entity_service(SERVICE_INCREMENT, {}, "async_increment")
SERVICE_INCREMENT, ENTITY_SERVICE_SCHEMA, "async_increment"
)
component.async_register_entity_service( component.async_register_entity_service(SERVICE_DECREMENT, {}, "async_decrement")
SERVICE_DECREMENT, ENTITY_SERVICE_SCHEMA, "async_decrement"
)
await component.async_add_entities(entities) await component.async_add_entities(entities)
return True return True

View File

@ -5,7 +5,6 @@ import voluptuous as vol
from homeassistant.const import CONF_ICON, CONF_NAME from homeassistant.const import CONF_ICON, CONF_NAME
import homeassistant.helpers.config_validation as cv 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.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
@ -22,9 +21,6 @@ ATTR_OPTIONS = "options"
SERVICE_SELECT_OPTION = "select_option" SERVICE_SELECT_OPTION = "select_option"
SERVICE_SELECT_OPTION_SCHEMA = ENTITY_SERVICE_SCHEMA.extend(
{vol.Required(ATTR_OPTION): cv.string}
)
SERVICE_SELECT_NEXT = "select_next" SERVICE_SELECT_NEXT = "select_next"
@ -32,14 +28,6 @@ SERVICE_SELECT_PREVIOUS = "select_previous"
SERVICE_SET_OPTIONS = "set_options" 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): def _cv_input_select(cfg):
"""Configure validation helper for input select (voluptuous).""" """Configure validation helper for input select (voluptuous)."""
@ -92,23 +80,27 @@ async def async_setup(hass, config):
return False return False
component.async_register_entity_service( 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( component.async_register_entity_service(
SERVICE_SELECT_NEXT, SERVICE_SELECT_NEXT, {}, lambda entity, call: entity.async_offset_index(1),
ENTITY_SERVICE_SCHEMA,
lambda entity, call: entity.async_offset_index(1),
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SELECT_PREVIOUS, SERVICE_SELECT_PREVIOUS, {}, lambda entity, call: entity.async_offset_index(-1),
ENTITY_SERVICE_SCHEMA,
lambda entity, call: entity.async_offset_index(-1),
) )
component.async_register_entity_service( 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) await component.async_add_entities(entities)

View File

@ -4,7 +4,6 @@ import logging
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
from homeassistant.const import ( from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
ATTR_MODE, ATTR_MODE,
@ -34,10 +33,6 @@ ATTR_PATTERN = "pattern"
SERVICE_SET_VALUE = "set_value" SERVICE_SET_VALUE = "set_value"
SERVICE_SET_VALUE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend(
{vol.Required(ATTR_VALUE): cv.string}
)
def _cv_input_text(cfg): def _cv_input_text(cfg):
"""Configure validation helper for input box (voluptuous).""" """Configure validation helper for input box (voluptuous)."""
@ -111,7 +106,7 @@ async def async_setup(hass, config):
return False return False
component.async_register_entity_service( 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) await component.async_add_entities(entities)

View File

@ -66,8 +66,9 @@ ATTR_INFRARED = "infrared"
ATTR_ZONES = "zones" ATTR_ZONES = "zones"
ATTR_POWER = "power" 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_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)),
ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]), ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]),
ATTR_POWER: cv.boolean, ATTR_POWER: cv.boolean,
@ -369,16 +370,11 @@ class LIFXManager:
async def async_service_to_entities(self, service): async def async_service_to_entities(self, service):
"""Return the known entities that a service call mentions.""" """Return the known entities that a service call mentions."""
entity_ids = await async_extract_entity_ids(self.hass, service) entity_ids = await async_extract_entity_ids(self.hass, service)
if entity_ids: return [
entities = [
entity entity
for entity in self.entities.values() for entity in self.entities.values()
if entity.entity_id in entity_ids if entity.entity_id in entity_ids
] ]
else:
entities = list(self.entities.values())
return entities
@callback @callback
def register(self, bulb): def register(self, bulb):

View File

@ -22,7 +22,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
ENTITY_SERVICE_SCHEMA, make_entity_service_schema,
) )
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
@ -93,8 +93,7 @@ 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 = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255))
VALID_BRIGHTNESS_PCT = vol.All(vol.Coerce(float), vol.Range(min=0, max=100)) VALID_BRIGHTNESS_PCT = vol.All(vol.Coerce(float), vol.Range(min=0, max=100))
LIGHT_TURN_ON_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( LIGHT_TURN_ON_SCHEMA = {
{
vol.Exclusive(ATTR_PROFILE, COLOR_GROUP): cv.string, vol.Exclusive(ATTR_PROFILE, COLOR_GROUP): cv.string,
ATTR_TRANSITION: VALID_TRANSITION, ATTR_TRANSITION: VALID_TRANSITION,
ATTR_BRIGHTNESS: VALID_BRIGHTNESS, ATTR_BRIGHTNESS: VALID_BRIGHTNESS,
@ -118,24 +117,13 @@ LIGHT_TURN_ON_SCHEMA = ENTITY_SERVICE_SCHEMA.extend(
vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP): vol.All( vol.Exclusive(ATTR_COLOR_TEMP, COLOR_GROUP): vol.All(
vol.Coerce(int), vol.Range(min=1) vol.Coerce(int), vol.Range(min=1)
), ),
vol.Exclusive(ATTR_KELVIN, COLOR_GROUP): vol.All( vol.Exclusive(ATTR_KELVIN, COLOR_GROUP): vol.All(vol.Coerce(int), vol.Range(min=0)),
vol.Coerce(int), vol.Range(min=0)
),
ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)), ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]), ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
ATTR_EFFECT: cv.string, ATTR_EFFECT: cv.string,
} }
)
LIGHT_TURN_OFF_SCHEMA = {
ATTR_TRANSITION: VALID_TRANSITION,
ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
}
LIGHT_TOGGLE_SCHEMA = LIGHT_TURN_ON_SCHEMA
PROFILE_SCHEMA = vol.Schema( PROFILE_SCHEMA = vol.Schema(
vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)) vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte))
) )
@ -268,15 +256,20 @@ async def async_setup(hass, config):
DOMAIN, DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
async_handle_light_on_service, 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( 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( component.async_register_entity_service(
SERVICE_TOGGLE, LIGHT_TOGGLE_SCHEMA, "async_toggle" SERVICE_TOGGLE, LIGHT_TURN_ON_SCHEMA, "async_toggle"
) )
return True return True

View File

@ -9,7 +9,7 @@ from homeassistant.loader import bind_hass
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA, make_entity_service_schema,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
@ -40,7 +40,7 @@ GROUP_NAME_ALL_LOCKS = "all locks"
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) 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 # Bitfield of features supported by the lock entity
SUPPORT_OPEN = 1 SUPPORT_OPEN = 1

View File

@ -2,6 +2,8 @@
import logging import logging
import voluptuous as vol 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 import MEDIA_PLAYER_PLAY_MEDIA_SCHEMA
from homeassistant.components.media_player.const import ( from homeassistant.components.media_player.const import (
@ -44,7 +46,10 @@ def setup(hass, config):
MediaExtractor(hass, config[DOMAIN], call.data).extract_and_send() MediaExtractor(hass, config[DOMAIN], call.data).extract_and_send()
hass.services.register( 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 return True
@ -98,9 +103,6 @@ class MediaExtractor:
def get_stream_selector(self): def get_stream_selector(self):
"""Return format selector for the media URL.""" """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}) ydl = YoutubeDL({"quiet": True, "logger": _LOGGER})
try: try:

View File

@ -40,7 +40,6 @@ from homeassistant.const import (
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, 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)) 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( MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = {
{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_TYPE): cv.string,
vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string, vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string,
vol.Optional(ATTR_MEDIA_ENQUEUE): cv.boolean, vol.Optional(ATTR_MEDIA_ENQUEUE): cv.boolean,
} }
)
MEDIA_PLAYER_SET_SHUFFLE_SCHEMA = ENTITY_SERVICE_SCHEMA.extend(
{vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean}
)
ATTR_TO_PROPERTY = [ ATTR_TO_PROPERTY = [
ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_LEVEL,
@ -223,65 +192,56 @@ async def async_setup(hass, config):
await component.async_setup(config) await component.async_setup(config)
component.async_register_entity_service( 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( 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( component.async_register_entity_service(
SERVICE_TOGGLE, SERVICE_TOGGLE, {}, "async_toggle", [SUPPORT_TURN_OFF | SUPPORT_TURN_ON],
ENTITY_SERVICE_SCHEMA,
"async_toggle",
[SUPPORT_TURN_OFF | SUPPORT_TURN_ON],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_UP, SERVICE_VOLUME_UP,
ENTITY_SERVICE_SCHEMA, {},
"async_volume_up", "async_volume_up",
[SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_DOWN, SERVICE_VOLUME_DOWN,
ENTITY_SERVICE_SCHEMA, {},
"async_volume_down", "async_volume_down",
[SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP], [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY_PAUSE,
ENTITY_SERVICE_SCHEMA, {},
"async_media_play_pause", "async_media_play_pause",
[SUPPORT_PLAY | SUPPORT_PAUSE], [SUPPORT_PLAY | SUPPORT_PAUSE],
) )
component.async_register_entity_service( 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( 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( 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( component.async_register_entity_service(
SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_NEXT_TRACK, {}, "async_media_next_track", [SUPPORT_NEXT_TRACK],
ENTITY_SERVICE_SCHEMA,
"async_media_next_track",
[SUPPORT_NEXT_TRACK],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK,
ENTITY_SERVICE_SCHEMA, {},
"async_media_previous_track", "async_media_previous_track",
[SUPPORT_PREVIOUS_TRACK], [SUPPORT_PREVIOUS_TRACK],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_CLEAR_PLAYLIST, SERVICE_CLEAR_PLAYLIST, {}, "async_clear_playlist", [SUPPORT_CLEAR_PLAYLIST],
ENTITY_SERVICE_SCHEMA,
"async_clear_playlist",
[SUPPORT_CLEAR_PLAYLIST],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_SET, 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( lambda entity, call: entity.async_set_volume_level(
volume=call.data[ATTR_MEDIA_VOLUME_LEVEL] volume=call.data[ATTR_MEDIA_VOLUME_LEVEL]
), ),
@ -289,7 +249,7 @@ async def async_setup(hass, config):
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_VOLUME_MUTE, SERVICE_VOLUME_MUTE,
MEDIA_PLAYER_MUTE_VOLUME_SCHEMA, {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean},
lambda entity, call: entity.async_mute_volume( lambda entity, call: entity.async_mute_volume(
mute=call.data[ATTR_MEDIA_VOLUME_MUTED] mute=call.data[ATTR_MEDIA_VOLUME_MUTED]
), ),
@ -297,7 +257,11 @@ async def async_setup(hass, config):
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_MEDIA_SEEK, 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( lambda entity, call: entity.async_media_seek(
position=call.data[ATTR_MEDIA_SEEK_POSITION] position=call.data[ATTR_MEDIA_SEEK_POSITION]
), ),
@ -305,13 +269,13 @@ async def async_setup(hass, config):
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SELECT_SOURCE, SERVICE_SELECT_SOURCE,
MEDIA_PLAYER_SELECT_SOURCE_SCHEMA, {vol.Required(ATTR_INPUT_SOURCE): cv.string},
"async_select_source", "async_select_source",
[SUPPORT_SELECT_SOURCE], [SUPPORT_SELECT_SOURCE],
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SELECT_SOUND_MODE, SERVICE_SELECT_SOUND_MODE,
MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA, {vol.Required(ATTR_SOUND_MODE): cv.string},
"async_select_sound_mode", "async_select_sound_mode",
[SUPPORT_SELECT_SOUND_MODE], [SUPPORT_SELECT_SOUND_MODE],
) )
@ -327,7 +291,7 @@ async def async_setup(hass, config):
) )
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_SHUFFLE_SET, SERVICE_SHUFFLE_SET,
MEDIA_PLAYER_SET_SHUFFLE_SCHEMA, {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean},
"async_set_shuffle", "async_set_shuffle",
[SUPPORT_SHUFFLE_SET], [SUPPORT_SHUFFLE_SET],
) )

View File

@ -17,7 +17,7 @@ from homeassistant.const import (
) )
from homeassistant.components import group from homeassistant.components import group
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA, make_entity_service_schema,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
@ -56,29 +56,10 @@ DEFAULT_HOLD_SECS = 0
SUPPORT_LEARN_COMMAND = 1 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} {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 @bind_hass
def is_on(hass, entity_id=None): def is_on(hass, entity_id=None):
@ -107,12 +88,27 @@ async def async_setup(hass, config):
) )
component.async_register_entity_service( 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( component.async_register_entity_service(
SERVICE_LEARN_COMMAND, 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", "async_learn_command",
) )

View File

@ -19,7 +19,7 @@ from homeassistant.loader import bind_hass
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
import homeassistant.helpers.config_validation as cv 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.service import async_set_service_schema
from homeassistant.helpers.script import Script from homeassistant.helpers.script import Script
@ -60,7 +60,7 @@ CONFIG_SCHEMA = vol.Schema(
) )
SCRIPT_SERVICE_SCHEMA = vol.Schema(dict) 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} {vol.Optional(ATTR_VARIABLES): dict}
) )
RELOAD_SERVICE_SCHEMA = vol.Schema({}) RELOAD_SERVICE_SCHEMA = vol.Schema({})

View File

@ -6,7 +6,6 @@ import voluptuous as vol
from homeassistant.const import CONF_ICON, CONF_NAME from homeassistant.const import CONF_ICON, CONF_NAME
import homeassistant.helpers.config_validation as cv 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.entity_component import EntityComponent
from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
@ -37,10 +36,6 @@ SERVICE_PAUSE = "pause"
SERVICE_CANCEL = "cancel" SERVICE_CANCEL = "cancel"
SERVICE_FINISH = "finish" 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( CONFIG_SCHEMA = vol.Schema(
{ {
DOMAIN: cv.schema_with_slug_keys( DOMAIN: cv.schema_with_slug_keys(
@ -80,17 +75,17 @@ async def async_setup(hass, config):
return False return False
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_START, SERVICE_SCHEMA_DURATION, "async_start" SERVICE_START,
) {
component.async_register_entity_service( vol.Optional(
SERVICE_PAUSE, ENTITY_SERVICE_SCHEMA, "async_pause" ATTR_DURATION, default=timedelta(DEFAULT_DURATION)
) ): cv.time_period
component.async_register_entity_service( },
SERVICE_CANCEL, ENTITY_SERVICE_SCHEMA, "async_cancel" "async_start",
)
component.async_register_entity_service(
SERVICE_FINISH, ENTITY_SERVICE_SCHEMA, "async_finish"
) )
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) await component.async_add_entities(entities)
return True return True

View File

@ -7,7 +7,6 @@ import voluptuous as vol
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import discovery 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.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
@ -39,11 +38,8 @@ ATTR_TARIFFS = "tariffs"
DEFAULT_OFFSET = timedelta(hours=0) 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.Required(CONF_SOURCE_SENSOR): cv.entity_id,
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
@ -110,16 +106,16 @@ async def async_setup(hass, config):
register_services = True register_services = True
if register_services: if register_services:
component.async_register_entity_service(SERVICE_RESET, {}, "async_reset_meters")
component.async_register_entity_service( 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( component.async_register_entity_service(
SERVICE_SELECT_TARIFF, SERVICE_SELECT_TARIFF_SCHEMA, "async_select_tariff" SERVICE_SELECT_NEXT_TARIFF, {}, "async_next_tariff"
)
component.async_register_entity_service(
SERVICE_SELECT_NEXT_TARIFF, ENTITY_SERVICE_SCHEMA, "async_next_tariff"
) )
return True return True

View File

@ -19,7 +19,7 @@ from homeassistant.const import ( # noqa: F401 # STATE_PAUSED/IDLE are API
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
ENTITY_SERVICE_SCHEMA, make_entity_service_schema,
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE, PLATFORM_SCHEMA_BASE,
) )
@ -55,16 +55,6 @@ SERVICE_START = "start"
SERVICE_PAUSE = "pause" SERVICE_PAUSE = "pause"
SERVICE_STOP = "stop" 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_CLEANING = "cleaning"
STATE_DOCKED = "docked" STATE_DOCKED = "docked"
@ -106,43 +96,32 @@ async def async_setup(hass, config):
await component.async_setup(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( 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( component.async_register_entity_service(
SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off" SERVICE_RETURN_TO_BASE, {}, "async_return_to_base"
)
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"
) )
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( component.async_register_entity_service(
SERVICE_SET_FAN_SPEED, SERVICE_SET_FAN_SPEED,
VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA, {vol.Required(ATTR_FAN_SPEED): cv.string},
"async_set_fan_speed", "async_set_fan_speed",
) )
component.async_register_entity_service( 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 return True

View File

@ -25,7 +25,7 @@ from homeassistant.const import (
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv 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 import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import track_time_interval from homeassistant.helpers.event import track_time_interval
@ -131,11 +131,11 @@ CONFIG_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA, 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 {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( SET_PAIRING_MODE_SCHEMA = vol.Schema(
{ {
@ -146,31 +146,31 @@ SET_PAIRING_MODE_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA, 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)} {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)} {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)} {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)} {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} {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} {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_MIN_VALUE): vol.Coerce(int),
vol.Optional(ATTR_MAX_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.Required(ATTR_VALUE): vol.Coerce(int),
vol.Optional(ATTR_LABELS): cv.ensure_list(cv.string), vol.Optional(ATTR_LABELS): cv.ensure_list(cv.string),

View File

@ -715,13 +715,24 @@ PLATFORM_SCHEMA = vol.Schema(
PLATFORM_SCHEMA_BASE = PLATFORM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA) PLATFORM_SCHEMA_BASE = PLATFORM_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA)
ENTITY_SERVICE_SCHEMA = vol.Schema(
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_ENTITY_ID): comp_entity_ids,
vol.Optional(ATTR_AREA_ID): vol.All(ensure_list, [str]), 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( EVENT_SCHEMA = vol.Schema(
{ {
vol.Optional(CONF_ALIAS): string, vol.Optional(CONF_ALIAS): string,

View File

@ -15,7 +15,7 @@ from homeassistant.const import (
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_per_platform, discovery 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.helpers.service import async_extract_entity_ids
from homeassistant.loader import bind_hass, async_get_integration from homeassistant.loader import bind_hass, async_get_integration
from homeassistant.util import slugify from homeassistant.util import slugify
@ -173,24 +173,16 @@ class EntityComponent:
async def async_extract_from_service(self, service, expand_group=True): async def async_extract_from_service(self, service, expand_group=True):
"""Extract all known and available entities from a service call. """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. Will return an empty list if entities specified but unknown.
This method must be run in the event loop. This method must be run in the event loop.
""" """
data_ent_id = service.data.get(ATTR_ENTITY_ID) data_ent_id = service.data.get(ATTR_ENTITY_ID)
if data_ent_id in (None, ENTITY_MATCH_ALL):
if data_ent_id is None: if data_ent_id is None:
self.logger.warning( return []
"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 == ENTITY_MATCH_ALL:
return [entity for entity in self.entities if entity.available] return [entity for entity in self.entities if entity.available]
entity_ids = await async_extract_entity_ids(self.hass, service, expand_group) 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): def async_register_entity_service(self, name, schema, func, required_features=None):
"""Register an entity service.""" """Register an entity service."""
if isinstance(schema, dict): if isinstance(schema, dict):
schema = ENTITY_SERVICE_SCHEMA.extend(schema) schema = make_entity_service_schema(schema)
async def handle_service(call): async def handle_service(call):
"""Handle the service.""" """Handle the service."""

View File

@ -260,19 +260,7 @@ async def entity_service_call(
else: else:
entity_perms = None entity_perms = None
# Are we trying to target all entities target_all_entities = call.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL
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
if not target_all_entities: if not target_all_entities:
# A set of entities we're trying to target. # A set of entities we're trying to target.

View File

@ -13,11 +13,12 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_AWAY, SERVICE_ALARM_ARM_AWAY,
SERVICE_ALARM_ARM_NIGHT, SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_ARM_CUSTOM_BYPASS, SERVICE_ALARM_ARM_CUSTOM_BYPASS,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass 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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -29,7 +30,7 @@ async def async_alarm_disarm(hass, code=None, entity_id=None):
@bind_hass @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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -40,7 +41,7 @@ def alarm_disarm(hass, code=None, entity_id=None):
hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data) 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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -52,7 +53,7 @@ async def async_alarm_arm_home(hass, code=None, entity_id=None):
@bind_hass @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.""" """Send the alarm the command for arm home."""
data = {} data = {}
if code: 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) 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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -75,7 +76,7 @@ async def async_alarm_arm_away(hass, code=None, entity_id=None):
@bind_hass @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.""" """Send the alarm the command for arm away."""
data = {} data = {}
if code: 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) 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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -98,7 +99,7 @@ async def async_alarm_arm_night(hass, code=None, entity_id=None):
@bind_hass @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.""" """Send the alarm the command for arm night."""
data = {} data = {}
if code: 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) 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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -121,7 +122,7 @@ async def async_alarm_trigger(hass, code=None, entity_id=None):
@bind_hass @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.""" """Send the alarm the command for trigger."""
data = {} data = {}
if code: if code:
@ -132,7 +133,7 @@ def alarm_trigger(hass, code=None, entity_id=None):
hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data) 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.""" """Send the alarm the command for disarm."""
data = {} data = {}
if code: if code:
@ -146,7 +147,7 @@ async def async_alarm_arm_custom_bypass(hass, code=None, entity_id=None):
@bind_hass @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.""" """Send the alarm the command for arm custom bypass."""
data = {} data = {}
if code: if code:

View File

@ -10,33 +10,34 @@ from homeassistant.const import (
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TOGGLE, SERVICE_TOGGLE,
SERVICE_RELOAD, SERVICE_RELOAD,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@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.""" """Turn on specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data) await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data)
@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 specified automation or all.""" """Turn off specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data) await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data)
@bind_hass @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.""" """Toggle specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data) await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data)
@bind_hass @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.""" """Trigger specified automation or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
await hass.services.async_call(DOMAIN, SERVICE_TRIGGER, data) await hass.services.async_call(DOMAIN, SERVICE_TRIGGER, data)

View File

@ -13,20 +13,25 @@ from homeassistant.components.camera.const import (
DATA_CAMERA_PREFS, DATA_CAMERA_PREFS,
PREF_PRELOAD_STREAM, 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.core import callback
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@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.""" """Turn off camera."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data) await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data)
@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 camera, and set operation mode.""" """Turn on camera, and set operation mode."""
data = {} data = {}
if entity_id is not None: if entity_id is not None:
@ -36,7 +41,7 @@ async def async_turn_on(hass, entity_id=None):
@bind_hass @bind_hass
def enable_motion_detection(hass, entity_id=None): def enable_motion_detection(hass, entity_id=ENTITY_MATCH_ALL):
"""Enable Motion Detection.""" """Enable Motion Detection."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_ENABLE_MOTION, data)) 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 @bind_hass
@callback @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.""" """Make a snapshot from a camera."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
data[ATTR_FILENAME] = filename data[ATTR_FILENAME] = filename

View File

@ -27,11 +27,12 @@ from homeassistant.const import (
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass 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.""" """Set new preset mode."""
data = {ATTR_PRESET_MODE: 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 @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.""" """Set new preset mode."""
data = {ATTR_PRESET_MODE: 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) 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.""" """Turn all or specified climate devices auxiliary heater on."""
data = {ATTR_AUX_HEAT: aux_heat} data = {ATTR_AUX_HEAT: aux_heat}
@ -63,7 +64,7 @@ async def async_set_aux_heat(hass, aux_heat, entity_id=None):
@bind_hass @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.""" """Turn all or specified climate devices auxiliary heater on."""
data = {ATTR_AUX_HEAT: aux_heat} 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( async def async_set_temperature(
hass, hass,
temperature=None, temperature=None,
entity_id=None, entity_id=ENTITY_MATCH_ALL,
target_temp_high=None, target_temp_high=None,
target_temp_low=None, target_temp_low=None,
hvac_mode=None, hvac_mode=None,
@ -103,7 +104,7 @@ async def async_set_temperature(
def set_temperature( def set_temperature(
hass, hass,
temperature=None, temperature=None,
entity_id=None, entity_id=ENTITY_MATCH_ALL,
target_temp_high=None, target_temp_high=None,
target_temp_low=None, target_temp_low=None,
hvac_mode=None, hvac_mode=None,
@ -124,7 +125,7 @@ def set_temperature(
hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, kwargs) 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.""" """Set new target humidity."""
data = {ATTR_HUMIDITY: humidity} data = {ATTR_HUMIDITY: humidity}
@ -135,7 +136,7 @@ async def async_set_humidity(hass, humidity, entity_id=None):
@bind_hass @bind_hass
def set_humidity(hass, humidity, entity_id=None): def set_humidity(hass, humidity, entity_id=ENTITY_MATCH_ALL):
"""Set new target humidity.""" """Set new target humidity."""
data = {ATTR_HUMIDITY: 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) 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.""" """Set all or specified climate devices fan mode on."""
data = {ATTR_FAN_MODE: fan} data = {ATTR_FAN_MODE: fan}
@ -156,7 +157,7 @@ async def async_set_fan_mode(hass, fan, entity_id=None):
@bind_hass @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.""" """Set all or specified climate devices fan mode on."""
data = {ATTR_FAN_MODE: fan} 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) 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.""" """Set new target operation mode."""
data = {ATTR_HVAC_MODE: hvac_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 @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.""" """Set new target operation mode."""
data = {ATTR_HVAC_MODE: hvac_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) 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.""" """Set new target swing mode."""
data = {ATTR_SWING_MODE: 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 @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.""" """Set new target swing mode."""
data = {ATTR_SWING_MODE: 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) 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.""" """Turn on device."""
data = {} 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) 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.""" """Turn off device."""
data = {} data = {}

View File

@ -62,10 +62,14 @@ async def test_turn_off(hass):
async def test_turn_off_without_entity_id(hass): async def test_turn_off_without_entity_id(hass):
"""Test light turn off all lights.""" """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) 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) assert not light.is_on(hass, ENTITY_LIGHT)

View File

@ -12,10 +12,15 @@ from homeassistant.components.fan import (
SERVICE_SET_DIRECTION, SERVICE_SET_DIRECTION,
SERVICE_SET_SPEED, 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.""" """Turn all or specified fan on."""
data = { data = {
key: value 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) 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.""" """Turn all or specified fan off."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} 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( async def async_oscillate(
hass, entity_id: str = None, should_oscillate: bool = True hass, entity_id=ENTITY_MATCH_ALL, should_oscillate: bool = True
) -> None: ) -> None:
"""Set oscillation on all or specified fan.""" """Set oscillation on all or specified fan."""
data = { data = {
@ -49,7 +54,7 @@ async def async_oscillate(
await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, data, blocking=True) 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.""" """Set speed for all or specified fan."""
data = { data = {
key: value 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( async def async_set_direction(
hass, entity_id: str = None, direction: str = None hass, entity_id=ENTITY_MATCH_ALL, direction: str = None
) -> None: ) -> None:
"""Set direction for all or specified fan.""" """Set direction for all or specified fan."""
data = { data = {

View File

@ -4,20 +4,20 @@ All containing methods are legacy helpers that should not be used by new
components. Instead call the service directly. components. Instead call the service directly.
""" """
from homeassistant.components.image_processing import DOMAIN, SERVICE_SCAN 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.core import callback
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@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.""" """Force process of all cameras or given entity."""
hass.add_job(async_scan, hass, entity_id) hass.add_job(async_scan, hass, entity_id)
@callback @callback
@bind_hass @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.""" """Force process of all cameras or given entity."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_SCAN, data)) hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_SCAN, data))

View File

@ -24,6 +24,7 @@ from homeassistant.const import (
SERVICE_TOGGLE, SERVICE_TOGGLE,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@ -31,7 +32,7 @@ from homeassistant.loader import bind_hass
@bind_hass @bind_hass
def turn_on( def turn_on(
hass, hass,
entity_id=None, entity_id=ENTITY_MATCH_ALL,
transition=None, transition=None,
brightness=None, brightness=None,
brightness_pct=None, brightness_pct=None,
@ -69,7 +70,7 @@ def turn_on(
async def async_turn_on( async def async_turn_on(
hass, hass,
entity_id=None, entity_id=ENTITY_MATCH_ALL,
transition=None, transition=None,
brightness=None, brightness=None,
brightness_pct=None, brightness_pct=None,
@ -110,12 +111,12 @@ async def async_turn_on(
@bind_hass @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.""" """Turn all or specified light off."""
hass.add_job(async_turn_off, hass, entity_id, transition) 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.""" """Turn all or specified light off."""
data = { data = {
key: value key: value
@ -127,12 +128,12 @@ async def async_turn_off(hass, entity_id=None, transition=None):
@bind_hass @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.""" """Toggle all or specified light."""
hass.add_job(async_toggle, hass, entity_id, transition) 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.""" """Toggle all or specified light."""
data = { data = {
key: value key: value

View File

@ -10,12 +10,13 @@ from homeassistant.const import (
SERVICE_LOCK, SERVICE_LOCK,
SERVICE_UNLOCK, SERVICE_UNLOCK,
SERVICE_OPEN, SERVICE_OPEN,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@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.""" """Lock all or specified locks."""
data = {} data = {}
if code: if code:
@ -26,7 +27,7 @@ def lock(hass, entity_id=None, code=None):
hass.services.call(DOMAIN, SERVICE_LOCK, data) 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.""" """Lock all or specified locks."""
data = {} data = {}
if code: if code:
@ -38,7 +39,7 @@ async def async_lock(hass, entity_id=None, code=None):
@bind_hass @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.""" """Unlock all or specified locks."""
data = {} data = {}
if code: if code:
@ -49,7 +50,7 @@ def unlock(hass, entity_id=None, code=None):
hass.services.call(DOMAIN, SERVICE_UNLOCK, data) 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.""" """Lock all or specified locks."""
data = {} data = {}
if code: if code:
@ -61,7 +62,7 @@ async def async_unlock(hass, entity_id=None, code=None):
@bind_hass @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.""" """Open all or specified locks."""
data = {} data = {}
if code: if code:
@ -72,7 +73,7 @@ def open_lock(hass, entity_id=None, code=None):
hass.services.call(DOMAIN, SERVICE_OPEN, data) 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.""" """Lock all or specified locks."""
data = {} data = {}
if code: if code:

View File

@ -32,47 +32,48 @@ from homeassistant.const import (
SERVICE_VOLUME_MUTE, SERVICE_VOLUME_MUTE,
SERVICE_VOLUME_SET, SERVICE_VOLUME_SET,
SERVICE_VOLUME_UP, SERVICE_VOLUME_UP,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@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.""" """Turn on specified media player or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TURN_ON, data) hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
@bind_hass @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.""" """Turn off specified media player or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
@bind_hass @bind_hass
def toggle(hass, entity_id=None): def toggle(hass, entity_id=ENTITY_MATCH_ALL):
"""Toggle specified media player or all.""" """Toggle specified media player or all."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_TOGGLE, data) hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
@bind_hass @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.""" """Send the media player the command for volume up."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_VOLUME_UP, data) hass.services.call(DOMAIN, SERVICE_VOLUME_UP, data)
@bind_hass @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.""" """Send the media player the command for volume down."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_VOLUME_DOWN, data) hass.services.call(DOMAIN, SERVICE_VOLUME_DOWN, data)
@bind_hass @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.""" """Send the media player the command for muting the volume."""
data = {ATTR_MEDIA_VOLUME_MUTED: mute} data = {ATTR_MEDIA_VOLUME_MUTED: mute}
@ -83,7 +84,7 @@ def mute_volume(hass, mute, entity_id=None):
@bind_hass @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.""" """Send the media player the command for setting the volume."""
data = {ATTR_MEDIA_VOLUME_LEVEL: volume} data = {ATTR_MEDIA_VOLUME_LEVEL: volume}
@ -94,49 +95,49 @@ def set_volume_level(hass, volume, entity_id=None):
@bind_hass @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.""" """Send the media player the command for play/pause."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, data) hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, data)
@bind_hass @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.""" """Send the media player the command for play/pause."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY, data) hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY, data)
@bind_hass @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.""" """Send the media player the command for pause."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_MEDIA_PAUSE, data) hass.services.call(DOMAIN, SERVICE_MEDIA_PAUSE, data)
@bind_hass @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.""" """Send the media player the command for stop."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_MEDIA_STOP, data) hass.services.call(DOMAIN, SERVICE_MEDIA_STOP, data)
@bind_hass @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.""" """Send the media player the command for next track."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_MEDIA_NEXT_TRACK, data) hass.services.call(DOMAIN, SERVICE_MEDIA_NEXT_TRACK, data)
@bind_hass @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.""" """Send the media player the command for prev track."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK, data) hass.services.call(DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK, data)
@bind_hass @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.""" """Send the media player the command to seek in current playing media."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
data[ATTR_MEDIA_SEEK_POSITION] = position data[ATTR_MEDIA_SEEK_POSITION] = position
@ -144,7 +145,7 @@ def media_seek(hass, position, entity_id=None):
@bind_hass @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.""" """Send the media player the command for playing media."""
data = {ATTR_MEDIA_CONTENT_TYPE: media_type, ATTR_MEDIA_CONTENT_ID: media_id} 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 @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.""" """Send the media player the command to select input source."""
data = {ATTR_INPUT_SOURCE: source} data = {ATTR_INPUT_SOURCE: source}
@ -169,7 +170,7 @@ def select_source(hass, source, entity_id=None):
@bind_hass @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.""" """Send the media player the command for clear playlist."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
hass.services.call(DOMAIN, SERVICE_CLEAR_PLAYLIST, data) hass.services.call(DOMAIN, SERVICE_CLEAR_PLAYLIST, data)

View File

@ -28,6 +28,7 @@ from homeassistant.const import (
CONF_PLATFORM, CONF_PLATFORM,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
STATE_UNKNOWN, STATE_UNKNOWN,
ENTITY_MATCH_ALL,
) )
from homeassistant.setup import async_setup_component 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}) 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.assert_called_once_with(COMMAND_TOPIC, "start", 0, False)
mqtt_mock.async_publish.reset_mock() 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.assert_called_once_with(COMMAND_TOPIC, "stop", 0, False)
mqtt_mock.async_publish.reset_mock() 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.assert_called_once_with(COMMAND_TOPIC, "pause", 0, False)
mqtt_mock.async_publish.reset_mock() 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.assert_called_once_with(COMMAND_TOPIC, "locate", 0, False)
mqtt_mock.async_publish.reset_mock() 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( mqtt_mock.async_publish.assert_called_once_with(
COMMAND_TOPIC, "clean_spot", 0, False COMMAND_TOPIC, "clean_spot", 0, False
) )
mqtt_mock.async_publish.reset_mock() 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( mqtt_mock.async_publish.assert_called_once_with(
COMMAND_TOPIC, "return_to_base", 0, False 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}) 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.assert_not_called()
mqtt_mock.async_publish.reset_mock() 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.assert_not_called()
mqtt_mock.async_publish.reset_mock() 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.assert_not_called()
mqtt_mock.async_publish.reset_mock() 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.assert_not_called()
mqtt_mock.async_publish.reset_mock() 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.assert_not_called()
mqtt_mock.async_publish.reset_mock() 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.assert_not_called()
mqtt_mock.async_publish.reset_mock() mqtt_mock.async_publish.reset_mock()

View File

@ -15,12 +15,17 @@ from homeassistant.components.remote import (
SERVICE_LEARN_COMMAND, SERVICE_LEARN_COMMAND,
SERVICE_SEND_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 from homeassistant.loader import bind_hass
@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.""" """Turn all or specified remote on."""
data = { data = {
key: value key: value
@ -31,7 +36,7 @@ def turn_on(hass, activity=None, entity_id=None):
@bind_hass @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.""" """Turn all or specified remote off."""
data = {} data = {}
if activity: if activity:
@ -45,7 +50,12 @@ def turn_off(hass, activity=None, entity_id=None):
@bind_hass @bind_hass
def send_command( 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.""" """Send a command to a device."""
data = {ATTR_COMMAND: command} data = {ATTR_COMMAND: command}
@ -66,7 +76,12 @@ def send_command(
@bind_hass @bind_hass
def learn_command( 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.""" """Learn a command from a device."""
data = {} data = {}

View File

@ -4,12 +4,12 @@ All containing methods are legacy helpers that should not be used by new
components. Instead call the service directly. components. Instead call the service directly.
""" """
from homeassistant.components.scene import DOMAIN 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 from homeassistant.loader import bind_hass
@bind_hass @bind_hass
def activate(hass, entity_id=None): def activate(hass, entity_id=ENTITY_MATCH_ALL):
"""Activate a scene.""" """Activate a scene."""
data = {} data = {}

View File

@ -551,7 +551,9 @@ async def test_set_turn_off(hass, air_conditioner):
await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner]) await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner])
state = hass.states.get("climate.air_conditioner") state = hass.states.get("climate.air_conditioner")
assert state.state == HVAC_MODE_HEAT_COOL 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") state = hass.states.get("climate.air_conditioner")
assert state.state == HVAC_MODE_OFF 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]) await setup_platform(hass, CLIMATE_DOMAIN, devices=[air_conditioner])
state = hass.states.get("climate.air_conditioner") state = hass.states.get("climate.air_conditioner")
assert state.state == HVAC_MODE_OFF 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") state = hass.states.get("climate.air_conditioner")
assert state.state == HVAC_MODE_HEAT_COOL assert state.state == HVAC_MODE_HEAT_COOL

View File

@ -114,7 +114,10 @@ async def test_set_cover_position(hass, device_factory):
await setup_platform(hass, COVER_DOMAIN, devices=[device]) await setup_platform(hass, COVER_DOMAIN, devices=[device])
# Act # Act
await hass.services.async_call( 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") 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]) await setup_platform(hass, COVER_DOMAIN, devices=[device])
# Act # Act
await hass.services.async_call( 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") state = hass.states.get("cover.shade")

View File

@ -4,29 +4,34 @@ All containing methods are legacy helpers that should not be used by new
components. Instead call the service directly. components. Instead call the service directly.
""" """
from homeassistant.components.switch import DOMAIN 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 from homeassistant.loader import bind_hass
@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.""" """Turn all or specified switch on."""
hass.add_job(async_turn_on, hass, entity_id) 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.""" """Turn all or specified switch on."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True)
@bind_hass @bind_hass
def turn_off(hass, entity_id=None): def turn_off(hass, entity_id=ENTITY_MATCH_ALL):
"""Turn all or specified switch off.""" """Turn all or specified switch off."""
hass.add_job(async_turn_off, hass, entity_id) 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.""" """Turn all or specified switch off."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data, blocking=True)

View File

@ -23,137 +23,138 @@ from homeassistant.const import (
SERVICE_TOGGLE, SERVICE_TOGGLE,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
ENTITY_MATCH_ALL,
) )
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
@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.""" """Turn all or specified vacuum on."""
hass.add_job(async_turn_on, hass, entity_id) 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.""" """Turn all or specified vacuum on."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data, blocking=True)
@bind_hass @bind_hass
def turn_off(hass, entity_id=None): def turn_off(hass, entity_id=ENTITY_MATCH_ALL):
"""Turn all or specified vacuum off.""" """Turn all or specified vacuum off."""
hass.add_job(async_turn_off, hass, entity_id) 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.""" """Turn all or specified vacuum off."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data, blocking=True)
@bind_hass @bind_hass
def toggle(hass, entity_id=None): def toggle(hass, entity_id=ENTITY_MATCH_ALL):
"""Toggle all or specified vacuum.""" """Toggle all or specified vacuum."""
hass.add_job(async_toggle, hass, entity_id) 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.""" """Toggle all or specified vacuum."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data, blocking=True)
@bind_hass @bind_hass
def locate(hass, entity_id=None): def locate(hass, entity_id=ENTITY_MATCH_ALL):
"""Locate all or specified vacuum.""" """Locate all or specified vacuum."""
hass.add_job(async_locate, hass, entity_id) 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.""" """Locate all or specified vacuum."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_LOCATE, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_LOCATE, data, blocking=True)
@bind_hass @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.""" """Tell all or specified vacuum to perform a spot clean-up."""
hass.add_job(async_clean_spot, hass, entity_id) 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.""" """Tell all or specified vacuum to perform a spot clean-up."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_CLEAN_SPOT, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_CLEAN_SPOT, data, blocking=True)
@bind_hass @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.""" """Tell all or specified vacuum to return to base."""
hass.add_job(async_return_to_base, hass, entity_id) 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.""" """Tell all or specified vacuum to return to base."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_RETURN_TO_BASE, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_RETURN_TO_BASE, data, blocking=True)
@bind_hass @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.""" """Tell all or specified vacuum to start or pause the current task."""
hass.add_job(async_start_pause, hass, entity_id) 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.""" """Tell all or specified vacuum to start or pause the current task."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_START_PAUSE, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_START_PAUSE, data, blocking=True)
@bind_hass @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.""" """Tell all or specified vacuum to start or resume the current task."""
hass.add_job(async_start, hass, entity_id) 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.""" """Tell all or specified vacuum to start or resume the current task."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_START, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_START, data, blocking=True)
@bind_hass @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.""" """Tell all or the specified vacuum to pause the current task."""
hass.add_job(async_pause, hass, entity_id) 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.""" """Tell all or the specified vacuum to pause the current task."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_PAUSE, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_PAUSE, data, blocking=True)
@bind_hass @bind_hass
def stop(hass, entity_id=None): def stop(hass, entity_id=ENTITY_MATCH_ALL):
"""Stop all or specified vacuum.""" """Stop all or specified vacuum."""
hass.add_job(async_stop, hass, entity_id) 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.""" """Stop all or specified vacuum."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
await hass.services.async_call(DOMAIN, SERVICE_STOP, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_STOP, data, blocking=True)
@bind_hass @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.""" """Set fan speed for all or specified vacuum."""
hass.add_job(async_set_fan_speed, hass, fan_speed, entity_id) 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.""" """Set fan speed for all or specified vacuum."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
data[ATTR_FAN_SPEED] = fan_speed data[ATTR_FAN_SPEED] = fan_speed
@ -161,12 +162,12 @@ async def async_set_fan_speed(hass, fan_speed, entity_id=None):
@bind_hass @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.""" """Send command to all or specified vacuum."""
hass.add_job(async_send_command, hass, command, params, entity_id) 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.""" """Send command to all or specified vacuum."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
data[ATTR_COMMAND] = command data[ATTR_COMMAND] = command

View File

@ -12,12 +12,12 @@ from homeassistant.components.water_heater import (
SERVICE_SET_TEMPERATURE, SERVICE_SET_TEMPERATURE,
SERVICE_SET_OPERATION_MODE, 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 from homeassistant.loader import bind_hass
@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.""" """Turn all or specified water_heater devices away mode on."""
data = {ATTR_AWAY_MODE: away_mode} data = {ATTR_AWAY_MODE: away_mode}
@ -28,7 +28,9 @@ def set_away_mode(hass, away_mode, entity_id=None):
@bind_hass @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.""" """Set new target temperature."""
kwargs = { kwargs = {
key: value key: value
@ -44,7 +46,7 @@ def set_temperature(hass, temperature=None, entity_id=None, operation_mode=None)
@bind_hass @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.""" """Set new target operation mode."""
data = {ATTR_OPERATION_MODE: operation_mode} data = {ATTR_OPERATION_MODE: operation_mode}

View File

@ -9,6 +9,7 @@ import asynctest
import pytest import pytest
import homeassistant.core as ha import homeassistant.core as ha
from homeassistant.const import ENTITY_MATCH_ALL
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import PlatformNotReady
from homeassistant.components import group from homeassistant.components import group
from homeassistant.helpers.entity_component import EntityComponent 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( assert ["test_domain.test_1", "test_domain.test_3"] == sorted(
ent.entity_id for ent in (await component.async_extract_from_service(call_1)) 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 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.""" """Test the extraction of everything from service."""
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
await component.async_add_entities( 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") 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)) 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") 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) 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): async def test_extract_all_use_match_all(hass, caplog):

View File

@ -11,7 +11,7 @@ import pytest
# To prevent circular import when running just this file # To prevent circular import when running just this file
import homeassistant.components # noqa: F401 import homeassistant.components # noqa: F401
from homeassistant import core as ha, exceptions 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 from homeassistant.setup import async_setup_component
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.auth.permissions import PolicyPermissions 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(entities=mock_entities)],
Mock(), Mock(),
ha.ServiceCall( 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, hass,
[Mock(entities=mock_entities)], [Mock(entities=mock_entities)],
Mock(), 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 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( 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( await service.entity_service_call(
hass, hass,
[Mock(entities=mock_entities)], [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 assert len(mock_service_platform_call.mock_calls) == 1
entities = mock_service_platform_call.mock_calls[0][1][2] entities = mock_service_platform_call.mock_calls[0][1][2]
assert entities == [ 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
async def test_register_admin_service(hass, hass_read_only_user, hass_admin_user): async def test_register_admin_service(hass, hass_read_only_user, hass_admin_user):