Log warning when entities referenced in service call not found (#31427)
* Raise entities not found error * Make it a warning, not an error * Add support for MATCH_ENTITY_NONE * Fix lint * Fix tests
This commit is contained in:
parent
201ea2557e
commit
f41623ca64
16 changed files with 339 additions and 89 deletions
|
@ -23,6 +23,7 @@ from homeassistant.const import (
|
|||
CONF_SENSORS,
|
||||
CONF_USERNAME,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
HTTP_BASIC_AUTHENTICATION,
|
||||
)
|
||||
from homeassistant.exceptions import Unauthorized, UnknownUser
|
||||
|
@ -236,6 +237,9 @@ def setup(hass, config):
|
|||
if have_permission(user, entity_id)
|
||||
]
|
||||
|
||||
if call.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_NONE:
|
||||
return []
|
||||
|
||||
call_ids = await async_extract_entity_ids(hass, call)
|
||||
entity_ids = []
|
||||
for entity_id in hass.data[DATA_AMCREST][CAMERAS]:
|
||||
|
|
|
@ -30,6 +30,7 @@ from homeassistant.const import (
|
|||
CONF_TIMEOUT,
|
||||
CONF_ZONE,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_PAUSED,
|
||||
|
@ -201,6 +202,10 @@ class DenonDevice(MediaPlayerDevice):
|
|||
def signal_handler(self, data):
|
||||
"""Handle domain-specific signal by calling appropriate method."""
|
||||
entity_ids = data[ATTR_ENTITY_ID]
|
||||
|
||||
if entity_ids == ENTITY_MATCH_NONE:
|
||||
return
|
||||
|
||||
if entity_ids == ENTITY_MATCH_ALL or self.entity_id in entity_ids:
|
||||
params = {
|
||||
key: value
|
||||
|
|
|
@ -11,6 +11,7 @@ from homeassistant.const import (
|
|||
CONF_PLATFORM,
|
||||
CONF_PORT,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
|
@ -136,7 +137,9 @@ DEL_ALL_LINK_SCHEMA = vol.Schema(
|
|||
|
||||
LOAD_ALDB_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_ENTITY_ID): vol.Any(cv.entity_id, ENTITY_MATCH_ALL),
|
||||
vol.Required(CONF_ENTITY_ID): vol.Any(
|
||||
cv.entity_id, ENTITY_MATCH_ALL, ENTITY_MATCH_NONE
|
||||
),
|
||||
vol.Optional(SRV_LOAD_DB_RELOAD, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -39,6 +39,7 @@ from homeassistant.const import (
|
|||
ATTR_ENTITY_ID,
|
||||
ATTR_MODE,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
|
@ -374,6 +375,9 @@ class LIFXManager:
|
|||
|
||||
async def async_service_to_entities(self, service):
|
||||
"""Return the known entities that a service call mentions."""
|
||||
if service.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_NONE:
|
||||
return []
|
||||
|
||||
if service.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL:
|
||||
return self.entities.values()
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ from homeassistant.components.media_player.const import (
|
|||
MEDIA_TYPE_MUSIC,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM, ENTITY_MATCH_ALL
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_per_platform, discovery
|
||||
|
@ -90,7 +90,7 @@ SCHEMA_SERVICE_SAY = vol.Schema(
|
|||
{
|
||||
vol.Required(ATTR_MESSAGE): cv.string,
|
||||
vol.Optional(ATTR_CACHE): cv.boolean,
|
||||
vol.Optional(ATTR_ENTITY_ID): cv.comp_entity_ids,
|
||||
vol.Required(ATTR_ENTITY_ID): cv.comp_entity_ids,
|
||||
vol.Optional(ATTR_LANGUAGE): cv.string,
|
||||
vol.Optional(ATTR_OPTIONS): dict,
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ async def async_setup(hass, config):
|
|||
|
||||
async def async_say_handle(service):
|
||||
"""Service handle for say."""
|
||||
entity_ids = service.data.get(ATTR_ENTITY_ID, ENTITY_MATCH_ALL)
|
||||
entity_ids = service.data[ATTR_ENTITY_ID]
|
||||
message = service.data.get(ATTR_MESSAGE)
|
||||
cache = service.data.get(ATTR_CACHE)
|
||||
language = service.data.get(ATTR_LANGUAGE)
|
||||
|
|
|
@ -29,6 +29,7 @@ from homeassistant.const import (
|
|||
CONF_HOST,
|
||||
CONF_NAME,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
|
@ -137,6 +138,9 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
|||
async def async_signal_handler(self, data):
|
||||
"""Handle domain-specific signal by calling appropriate method."""
|
||||
entity_ids = data[ATTR_ENTITY_ID]
|
||||
if entity_ids == ENTITY_MATCH_NONE:
|
||||
return
|
||||
|
||||
if entity_ids == ENTITY_MATCH_ALL or self.entity_id in entity_ids:
|
||||
params = {
|
||||
key: value
|
||||
|
|
|
@ -16,6 +16,7 @@ PLATFORM_FORMAT = "{platform}.{domain}"
|
|||
MATCH_ALL = "*"
|
||||
|
||||
# Entity target all constant
|
||||
ENTITY_MATCH_NONE = "none"
|
||||
ENTITY_MATCH_ALL = "all"
|
||||
|
||||
# If no name is specified
|
||||
|
|
|
@ -52,6 +52,7 @@ from homeassistant.const import (
|
|||
CONF_UNIT_SYSTEM_METRIC,
|
||||
CONF_VALUE_TEMPLATE,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
SUN_EVENT_SUNRISE,
|
||||
SUN_EVENT_SUNSET,
|
||||
TEMP_CELSIUS,
|
||||
|
@ -231,7 +232,9 @@ def entity_ids(value: Union[str, List]) -> List[str]:
|
|||
return [entity_id(ent_id) for ent_id in value]
|
||||
|
||||
|
||||
comp_entity_ids = vol.Any(vol.All(vol.Lower, ENTITY_MATCH_ALL), entity_ids)
|
||||
comp_entity_ids = vol.Any(
|
||||
vol.All(vol.Lower, vol.Any(ENTITY_MATCH_ALL, ENTITY_MATCH_NONE)), entity_ids
|
||||
)
|
||||
|
||||
|
||||
def entity_domain(domain: str) -> Callable[[Any], str]:
|
||||
|
@ -736,7 +739,9 @@ def make_entity_service_schema(
|
|||
{
|
||||
**schema,
|
||||
vol.Optional(ATTR_ENTITY_ID): comp_entity_ids,
|
||||
vol.Optional(ATTR_AREA_ID): vol.All(ensure_list, [str]),
|
||||
vol.Optional(ATTR_AREA_ID): vol.Any(
|
||||
ENTITY_MATCH_NONE, vol.All(ensure_list, [str])
|
||||
),
|
||||
},
|
||||
extra=extra,
|
||||
),
|
||||
|
|
|
@ -7,7 +7,12 @@ from typing import Callable
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.auth.permissions.const import CAT_ENTITIES, POLICY_CONTROL
|
||||
from homeassistant.const import ATTR_AREA_ID, ATTR_ENTITY_ID, ENTITY_MATCH_ALL
|
||||
from homeassistant.const import (
|
||||
ATTR_AREA_ID,
|
||||
ATTR_ENTITY_ID,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
)
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.exceptions import (
|
||||
HomeAssistantError,
|
||||
|
@ -121,11 +126,25 @@ async def async_extract_entities(hass, entities, service_call, expand_group=True
|
|||
|
||||
entity_ids = await async_extract_entity_ids(hass, service_call, expand_group)
|
||||
|
||||
return [
|
||||
entity
|
||||
for entity in entities
|
||||
if entity.available and entity.entity_id in entity_ids
|
||||
]
|
||||
found = []
|
||||
|
||||
for entity in entities:
|
||||
if entity.entity_id not in entity_ids:
|
||||
continue
|
||||
|
||||
entity_ids.remove(entity.entity_id)
|
||||
|
||||
if not entity.available:
|
||||
continue
|
||||
|
||||
found.append(entity)
|
||||
|
||||
if entity_ids:
|
||||
_LOGGER.warning(
|
||||
"Unable to find referenced entities %s", ", ".join(sorted(entity_ids))
|
||||
)
|
||||
|
||||
return found
|
||||
|
||||
|
||||
@bind_hass
|
||||
|
@ -137,12 +156,15 @@ async def async_extract_entity_ids(hass, service_call, expand_group=True):
|
|||
entity_ids = service_call.data.get(ATTR_ENTITY_ID)
|
||||
area_ids = service_call.data.get(ATTR_AREA_ID)
|
||||
|
||||
if not entity_ids and not area_ids:
|
||||
return []
|
||||
|
||||
extracted = set()
|
||||
|
||||
if entity_ids:
|
||||
if entity_ids in (None, ENTITY_MATCH_NONE) and area_ids in (
|
||||
None,
|
||||
ENTITY_MATCH_NONE,
|
||||
):
|
||||
return extracted
|
||||
|
||||
if entity_ids and entity_ids != ENTITY_MATCH_NONE:
|
||||
# Entity ID attr can be a list or a string
|
||||
if isinstance(entity_ids, str):
|
||||
entity_ids = [entity_ids]
|
||||
|
@ -152,7 +174,7 @@ async def async_extract_entity_ids(hass, service_call, expand_group=True):
|
|||
|
||||
extracted.update(entity_ids)
|
||||
|
||||
if area_ids:
|
||||
if area_ids and area_ids != ENTITY_MATCH_NONE:
|
||||
if isinstance(area_ids, str):
|
||||
area_ids = [area_ids]
|
||||
|
||||
|
@ -342,6 +364,16 @@ async def entity_service_call(hass, platforms, func, call, required_features=Non
|
|||
|
||||
platforms_entities.append(platform_entities)
|
||||
|
||||
if not target_all_entities:
|
||||
for platform_entities in platforms_entities:
|
||||
for entity in platform_entities:
|
||||
entity_ids.remove(entity.entity_id)
|
||||
|
||||
if entity_ids:
|
||||
_LOGGER.warning(
|
||||
"Unable to find referenced entities %s", ", ".join(sorted(entity_ids))
|
||||
)
|
||||
|
||||
tasks = [
|
||||
_handle_service_platform_call(
|
||||
hass, func, data, entities, call.context, required_features
|
||||
|
|
|
@ -65,7 +65,10 @@ class TestTTSGooglePlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"google_translate_say",
|
||||
{tts.ATTR_MESSAGE: "90% of I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -89,7 +92,10 @@ class TestTTSGooglePlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"google_translate_say",
|
||||
{tts.ATTR_MESSAGE: "90% of I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -115,6 +121,7 @@ class TestTTSGooglePlatform:
|
|||
tts.DOMAIN,
|
||||
"google_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
||||
tts.ATTR_LANGUAGE: "de",
|
||||
},
|
||||
|
@ -139,7 +146,10 @@ class TestTTSGooglePlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"google_translate_say",
|
||||
{tts.ATTR_MESSAGE: "90% of I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -161,7 +171,10 @@ class TestTTSGooglePlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"google_translate_say",
|
||||
{tts.ATTR_MESSAGE: "90% of I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -193,6 +206,7 @@ class TestTTSGooglePlatform:
|
|||
tts.DOMAIN,
|
||||
"google_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: (
|
||||
"I person is on front of your door."
|
||||
"I person is on front of your door."
|
||||
|
@ -203,7 +217,7 @@ class TestTTSGooglePlatform:
|
|||
"I person is on front of your door."
|
||||
"I person is on front of your door."
|
||||
"I person is on front of your door."
|
||||
)
|
||||
),
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
|
|
@ -66,7 +66,12 @@ class TestTTSMaryTTSPlatform:
|
|||
|
||||
with patch("http.client.HTTPConnection", return_value=conn):
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "marytts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"marytts_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "HomeAssistant",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -93,7 +98,12 @@ class TestTTSMaryTTSPlatform:
|
|||
|
||||
with patch("http.client.HTTPConnection", return_value=conn):
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "marytts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"marytts_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "HomeAssistant",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -123,7 +133,12 @@ class TestTTSMaryTTSPlatform:
|
|||
|
||||
with patch("http.client.HTTPConnection", return_value=conn):
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "marytts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"marytts_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "HomeAssistant",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
|
|
@ -95,7 +95,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -103,13 +106,13 @@ class TestTTS:
|
|||
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC
|
||||
assert calls[0].data[
|
||||
ATTR_MEDIA_CONTENT_ID
|
||||
] == "{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3".format(
|
||||
] == "{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3".format(
|
||||
self.hass.config.api.base_url
|
||||
)
|
||||
assert os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -125,7 +128,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -133,13 +139,13 @@ class TestTTS:
|
|||
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC
|
||||
assert calls[0].data[
|
||||
ATTR_MEDIA_CONTENT_ID
|
||||
] == "{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3".format(
|
||||
] == "{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3".format(
|
||||
self.hass.config.api.base_url
|
||||
)
|
||||
assert os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -163,7 +169,8 @@ class TestTTS:
|
|||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
tts.ATTR_LANGUAGE: "de",
|
||||
},
|
||||
)
|
||||
|
@ -173,13 +180,13 @@ class TestTTS:
|
|||
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC
|
||||
assert calls[0].data[
|
||||
ATTR_MEDIA_CONTENT_ID
|
||||
] == "{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3".format(
|
||||
] == "{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3".format(
|
||||
self.hass.config.api.base_url
|
||||
)
|
||||
assert os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -196,7 +203,8 @@ class TestTTS:
|
|||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
tts.ATTR_LANGUAGE: "lang",
|
||||
},
|
||||
)
|
||||
|
@ -206,7 +214,7 @@ class TestTTS:
|
|||
assert not os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_lang_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_lang_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -223,7 +231,8 @@ class TestTTS:
|
|||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
tts.ATTR_LANGUAGE: "de",
|
||||
tts.ATTR_OPTIONS: {"voice": "alex"},
|
||||
},
|
||||
|
@ -236,13 +245,13 @@ class TestTTS:
|
|||
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC
|
||||
assert calls[0].data[
|
||||
ATTR_MEDIA_CONTENT_ID
|
||||
] == "{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_de_{}_demo.mp3".format(
|
||||
] == "{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{}_demo.mp3".format(
|
||||
self.hass.config.api.base_url, opt_hash
|
||||
)
|
||||
assert os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_{0}_demo.mp3".format(
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{0}_demo.mp3".format(
|
||||
opt_hash
|
||||
),
|
||||
)
|
||||
|
@ -265,7 +274,8 @@ class TestTTS:
|
|||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
tts.ATTR_LANGUAGE: "de",
|
||||
},
|
||||
)
|
||||
|
@ -277,13 +287,13 @@ class TestTTS:
|
|||
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC
|
||||
assert calls[0].data[
|
||||
ATTR_MEDIA_CONTENT_ID
|
||||
] == "{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_de_{}_demo.mp3".format(
|
||||
] == "{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{}_demo.mp3".format(
|
||||
self.hass.config.api.base_url, opt_hash
|
||||
)
|
||||
assert os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_{0}_demo.mp3".format(
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{0}_demo.mp3".format(
|
||||
opt_hash
|
||||
),
|
||||
)
|
||||
|
@ -302,7 +312,8 @@ class TestTTS:
|
|||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
tts.ATTR_LANGUAGE: "de",
|
||||
tts.ATTR_OPTIONS: {"speed": 1},
|
||||
},
|
||||
|
@ -315,7 +326,7 @@ class TestTTS:
|
|||
assert not os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_{0}_demo.mp3".format(
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{0}_demo.mp3".format(
|
||||
opt_hash
|
||||
),
|
||||
)
|
||||
|
@ -333,7 +344,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -341,7 +355,7 @@ class TestTTS:
|
|||
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC
|
||||
assert (
|
||||
calls[0].data[ATTR_MEDIA_CONTENT_ID] == "http://fnord"
|
||||
"/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd"
|
||||
"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||
"_en_-_demo.mp3"
|
||||
)
|
||||
|
||||
|
@ -357,7 +371,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -365,7 +382,7 @@ class TestTTS:
|
|||
assert os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -375,7 +392,7 @@ class TestTTS:
|
|||
assert not os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -393,7 +410,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -401,7 +421,7 @@ class TestTTS:
|
|||
req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID])
|
||||
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
||||
demo_data = tts.SpeechManager.write_tags(
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
demo_data,
|
||||
self.demo_provider,
|
||||
"AI person is in front of your door.",
|
||||
|
@ -425,7 +445,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -433,10 +456,10 @@ class TestTTS:
|
|||
req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID])
|
||||
_, demo_data = self.demo_provider.get_tts_audio("bla", "de")
|
||||
demo_data = tts.SpeechManager.write_tags(
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3",
|
||||
demo_data,
|
||||
self.demo_provider,
|
||||
"I person is on front of your door.",
|
||||
"There is someone at the door.",
|
||||
"de",
|
||||
None,
|
||||
)
|
||||
|
@ -453,7 +476,7 @@ class TestTTS:
|
|||
self.hass.start()
|
||||
|
||||
url = (
|
||||
"{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3"
|
||||
"{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3"
|
||||
).format(self.hass.config.api.base_url)
|
||||
|
||||
req = requests.get(url)
|
||||
|
@ -487,7 +510,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -495,7 +521,7 @@ class TestTTS:
|
|||
assert not os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -512,7 +538,8 @@ class TestTTS:
|
|||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
tts.ATTR_CACHE: False,
|
||||
},
|
||||
)
|
||||
|
@ -522,7 +549,7 @@ class TestTTS:
|
|||
assert not os.path.isfile(
|
||||
os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -533,7 +560,7 @@ class TestTTS:
|
|||
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
||||
cache_file = os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
|
||||
os.mkdir(self.default_tts_cache)
|
||||
|
@ -552,14 +579,17 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data[
|
||||
ATTR_MEDIA_CONTENT_ID
|
||||
] == "{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3".format(
|
||||
] == "{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3".format(
|
||||
self.hass.config.api.base_url
|
||||
)
|
||||
|
||||
|
@ -579,7 +609,10 @@ class TestTTS:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"demo_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "There is someone at the door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -590,7 +623,7 @@ class TestTTS:
|
|||
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
||||
cache_file = os.path.join(
|
||||
self.default_tts_cache,
|
||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
||||
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||
)
|
||||
|
||||
os.mkdir(self.default_tts_cache)
|
||||
|
@ -605,7 +638,7 @@ class TestTTS:
|
|||
self.hass.start()
|
||||
|
||||
url = (
|
||||
"{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3"
|
||||
"{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3"
|
||||
).format(self.hass.config.api.base_url)
|
||||
|
||||
req = requests.get(url)
|
||||
|
@ -622,14 +655,15 @@ async def test_setup_component_and_web_get_url(hass, hass_client):
|
|||
client = await hass_client()
|
||||
|
||||
url = "/api/tts_get_url"
|
||||
data = {"platform": "demo", "message": "I person is on front of your door."}
|
||||
data = {"platform": "demo", "message": "There is someone at the door."}
|
||||
|
||||
req = await client.post(url, json=data)
|
||||
assert req.status == 200
|
||||
response = await req.json()
|
||||
assert response.get("url") == (
|
||||
"{}/api/tts_proxy/265944c108cbb00b2a62"
|
||||
"1be5930513e03a0bb2cd_en_-_demo.mp3".format(hass.config.api.base_url)
|
||||
"{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3".format(
|
||||
hass.config.api.base_url
|
||||
)
|
||||
)
|
||||
|
||||
tts_cache = hass.config.path(tts.DEFAULT_CACHE_DIR)
|
||||
|
@ -646,7 +680,7 @@ async def test_setup_component_and_web_get_url_bad_config(hass, hass_client):
|
|||
client = await hass_client()
|
||||
|
||||
url = "/api/tts_get_url"
|
||||
data = {"message": "I person is on front of your door."}
|
||||
data = {"message": "There is someone at the door."}
|
||||
|
||||
req = await client.post(url, json=data)
|
||||
assert req.status == 400
|
||||
|
|
|
@ -67,7 +67,10 @@ class TestTTSVoiceRSSPlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"voicerss_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -97,7 +100,10 @@ class TestTTSVoiceRSSPlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"voicerss_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -121,6 +127,7 @@ class TestTTSVoiceRSSPlatform:
|
|||
tts.DOMAIN,
|
||||
"voicerss_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
tts.ATTR_LANGUAGE: "de-de",
|
||||
},
|
||||
|
@ -145,7 +152,10 @@ class TestTTSVoiceRSSPlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"voicerss_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -167,7 +177,10 @@ class TestTTSVoiceRSSPlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"voicerss_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -194,7 +207,10 @@ class TestTTSVoiceRSSPlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"voicerss_say",
|
||||
{tts.ATTR_MESSAGE: "I person is on front of your door."},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
|
|
@ -67,7 +67,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -103,7 +105,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -135,7 +139,11 @@ class TestTTSYandexPlatform:
|
|||
self.hass.services.call(
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{tts.ATTR_MESSAGE: "HomeAssistant", tts.ATTR_LANGUAGE: "ru-RU"},
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "HomeAssistant",
|
||||
tts.ATTR_LANGUAGE: "ru-RU",
|
||||
},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -165,7 +173,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -195,7 +205,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -230,7 +242,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -266,7 +280,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -298,7 +314,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -330,7 +348,9 @@ class TestTTSYandexPlatform:
|
|||
setup_component(self.hass, tts.DOMAIN, config)
|
||||
|
||||
self.hass.services.call(
|
||||
tts.DOMAIN, "yandextts_say", {tts.ATTR_MESSAGE: "HomeAssistant"}
|
||||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{"entity_id": "media_player.something", tts.ATTR_MESSAGE: "HomeAssistant"},
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
|
@ -362,6 +382,7 @@ class TestTTSYandexPlatform:
|
|||
tts.DOMAIN,
|
||||
"yandextts_say",
|
||||
{
|
||||
"entity_id": "media_player.something",
|
||||
tts.ATTR_MESSAGE: "HomeAssistant",
|
||||
"options": {"emotion": "evil", "speed": 2},
|
||||
},
|
||||
|
|
|
@ -7,8 +7,9 @@ from unittest.mock import Mock, patch
|
|||
|
||||
import asynctest
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import ENTITY_MATCH_ALL
|
||||
from homeassistant.const import ENTITY_MATCH_ALL, ENTITY_MATCH_NONE
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers import discovery
|
||||
|
@ -223,10 +224,21 @@ async def test_extract_from_service_fails_if_no_entity_id(hass):
|
|||
[MockEntity(name="test_1"), MockEntity(name="test_2")]
|
||||
)
|
||||
|
||||
call = ha.ServiceCall("test", "service")
|
||||
|
||||
assert [] == sorted(
|
||||
ent.entity_id for ent in (await component.async_extract_from_service(call))
|
||||
assert (
|
||||
await component.async_extract_from_service(ha.ServiceCall("test", "service"))
|
||||
== []
|
||||
)
|
||||
assert (
|
||||
await component.async_extract_from_service(
|
||||
ha.ServiceCall("test", "service", {"entity_id": ENTITY_MATCH_NONE})
|
||||
)
|
||||
== []
|
||||
)
|
||||
assert (
|
||||
await component.async_extract_from_service(
|
||||
ha.ServiceCall("test", "service", {"area_id": ENTITY_MATCH_NONE})
|
||||
)
|
||||
== []
|
||||
)
|
||||
|
||||
|
||||
|
@ -429,3 +441,53 @@ async def test_extract_all_use_match_all(hass, caplog):
|
|||
assert (
|
||||
"Not passing an entity ID to a service to target all entities is deprecated"
|
||||
) not in caplog.text
|
||||
|
||||
|
||||
async def test_register_entity_service(hass):
|
||||
"""Test not expanding a group."""
|
||||
entity = MockEntity(entity_id=f"{DOMAIN}.entity")
|
||||
calls = []
|
||||
|
||||
@ha.callback
|
||||
def appender(**kwargs):
|
||||
calls.append(kwargs)
|
||||
|
||||
entity.async_called_by_service = appender
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
await component.async_add_entities([entity])
|
||||
|
||||
component.async_register_entity_service(
|
||||
"hello", {"some": str}, "async_called_by_service"
|
||||
)
|
||||
|
||||
with pytest.raises(vol.Invalid):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"hello",
|
||||
{"entity_id": entity.entity_id, "invalid": "data"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(calls) == 0
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN, "hello", {"entity_id": entity.entity_id, "some": "data"}, blocking=True
|
||||
)
|
||||
assert len(calls) == 1
|
||||
assert calls[0] == {"some": "data"}
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN, "hello", {"entity_id": ENTITY_MATCH_ALL, "some": "data"}, blocking=True
|
||||
)
|
||||
assert len(calls) == 2
|
||||
assert calls[1] == {"some": "data"}
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN, "hello", {"entity_id": ENTITY_MATCH_NONE, "some": "data"}, blocking=True
|
||||
)
|
||||
assert len(calls) == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN, "hello", {"area_id": ENTITY_MATCH_NONE, "some": "data"}, blocking=True
|
||||
)
|
||||
assert len(calls) == 2
|
||||
|
|
|
@ -12,7 +12,13 @@ import voluptuous as vol
|
|||
from homeassistant import core as ha, exceptions
|
||||
from homeassistant.auth.permissions import PolicyPermissions
|
||||
import homeassistant.components # noqa: F401
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ENTITY_MATCH_ALL, STATE_OFF, STATE_ON
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dev_reg,
|
||||
entity_registry as ent_reg,
|
||||
|
@ -252,6 +258,14 @@ async def test_extract_entity_ids(hass):
|
|||
hass, call, expand_group=False
|
||||
)
|
||||
|
||||
assert (
|
||||
await service.async_extract_entity_ids(
|
||||
hass,
|
||||
ha.ServiceCall("light", "turn_on", {ATTR_ENTITY_ID: ENTITY_MATCH_NONE}),
|
||||
)
|
||||
== set()
|
||||
)
|
||||
|
||||
|
||||
async def test_extract_entity_ids_from_area(hass, area_mock):
|
||||
"""Test extract_entity_ids method with areas."""
|
||||
|
@ -266,6 +280,13 @@ async def test_extract_entity_ids_from_area(hass, area_mock):
|
|||
"light.diff_area",
|
||||
} == await service.async_extract_entity_ids(hass, call)
|
||||
|
||||
assert (
|
||||
await service.async_extract_entity_ids(
|
||||
hass, ha.ServiceCall("light", "turn_on", {"area_id": ENTITY_MATCH_NONE})
|
||||
)
|
||||
== set()
|
||||
)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_get_all_descriptions(hass):
|
||||
|
@ -742,6 +763,15 @@ async def test_extract_from_service_available_device(hass):
|
|||
for ent in (await service.async_extract_entities(hass, entities, call_2))
|
||||
]
|
||||
|
||||
assert (
|
||||
await service.async_extract_entities(
|
||||
hass,
|
||||
entities,
|
||||
ha.ServiceCall("test", "service", data={"entity_id": ENTITY_MATCH_NONE},),
|
||||
)
|
||||
== []
|
||||
)
|
||||
|
||||
|
||||
async def test_extract_from_service_empty_if_no_entity_id(hass):
|
||||
"""Test the extraction from service without specifying entity."""
|
||||
|
|
Loading…
Add table
Reference in a new issue