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_SENSORS,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
ENTITY_MATCH_ALL,
|
ENTITY_MATCH_ALL,
|
||||||
|
ENTITY_MATCH_NONE,
|
||||||
HTTP_BASIC_AUTHENTICATION,
|
HTTP_BASIC_AUTHENTICATION,
|
||||||
)
|
)
|
||||||
from homeassistant.exceptions import Unauthorized, UnknownUser
|
from homeassistant.exceptions import Unauthorized, UnknownUser
|
||||||
|
@ -236,6 +237,9 @@ def setup(hass, config):
|
||||||
if have_permission(user, entity_id)
|
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)
|
call_ids = await async_extract_entity_ids(hass, call)
|
||||||
entity_ids = []
|
entity_ids = []
|
||||||
for entity_id in hass.data[DATA_AMCREST][CAMERAS]:
|
for entity_id in hass.data[DATA_AMCREST][CAMERAS]:
|
||||||
|
|
|
@ -30,6 +30,7 @@ from homeassistant.const import (
|
||||||
CONF_TIMEOUT,
|
CONF_TIMEOUT,
|
||||||
CONF_ZONE,
|
CONF_ZONE,
|
||||||
ENTITY_MATCH_ALL,
|
ENTITY_MATCH_ALL,
|
||||||
|
ENTITY_MATCH_NONE,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
STATE_PAUSED,
|
STATE_PAUSED,
|
||||||
|
@ -201,6 +202,10 @@ class DenonDevice(MediaPlayerDevice):
|
||||||
def signal_handler(self, data):
|
def signal_handler(self, data):
|
||||||
"""Handle domain-specific signal by calling appropriate method."""
|
"""Handle domain-specific signal by calling appropriate method."""
|
||||||
entity_ids = data[ATTR_ENTITY_ID]
|
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:
|
if entity_ids == ENTITY_MATCH_ALL or self.entity_id in entity_ids:
|
||||||
params = {
|
params = {
|
||||||
key: value
|
key: value
|
||||||
|
|
|
@ -11,6 +11,7 @@ from homeassistant.const import (
|
||||||
CONF_PLATFORM,
|
CONF_PLATFORM,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
ENTITY_MATCH_ALL,
|
ENTITY_MATCH_ALL,
|
||||||
|
ENTITY_MATCH_NONE,
|
||||||
)
|
)
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
|
@ -136,7 +137,9 @@ DEL_ALL_LINK_SCHEMA = vol.Schema(
|
||||||
|
|
||||||
LOAD_ALDB_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,
|
vol.Optional(SRV_LOAD_DB_RELOAD, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -39,6 +39,7 @@ from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_MODE,
|
ATTR_MODE,
|
||||||
ENTITY_MATCH_ALL,
|
ENTITY_MATCH_ALL,
|
||||||
|
ENTITY_MATCH_NONE,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
@ -374,6 +375,9 @@ 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."""
|
||||||
|
if service.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_NONE:
|
||||||
|
return []
|
||||||
|
|
||||||
if service.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL:
|
if service.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL:
|
||||||
return self.entities.values()
|
return self.entities.values()
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ from homeassistant.components.media_player.const import (
|
||||||
MEDIA_TYPE_MUSIC,
|
MEDIA_TYPE_MUSIC,
|
||||||
SERVICE_PLAY_MEDIA,
|
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.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
|
||||||
|
@ -90,7 +90,7 @@ SCHEMA_SERVICE_SAY = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(ATTR_MESSAGE): cv.string,
|
vol.Required(ATTR_MESSAGE): cv.string,
|
||||||
vol.Optional(ATTR_CACHE): cv.boolean,
|
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_LANGUAGE): cv.string,
|
||||||
vol.Optional(ATTR_OPTIONS): dict,
|
vol.Optional(ATTR_OPTIONS): dict,
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ async def async_setup(hass, config):
|
||||||
|
|
||||||
async def async_say_handle(service):
|
async def async_say_handle(service):
|
||||||
"""Service handle for say."""
|
"""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)
|
message = service.data.get(ATTR_MESSAGE)
|
||||||
cache = service.data.get(ATTR_CACHE)
|
cache = service.data.get(ATTR_CACHE)
|
||||||
language = service.data.get(ATTR_LANGUAGE)
|
language = service.data.get(ATTR_LANGUAGE)
|
||||||
|
|
|
@ -29,6 +29,7 @@ from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
ENTITY_MATCH_ALL,
|
ENTITY_MATCH_ALL,
|
||||||
|
ENTITY_MATCH_NONE,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
)
|
)
|
||||||
|
@ -137,6 +138,9 @@ class LgWebOSMediaPlayerEntity(MediaPlayerDevice):
|
||||||
async def async_signal_handler(self, data):
|
async def async_signal_handler(self, data):
|
||||||
"""Handle domain-specific signal by calling appropriate method."""
|
"""Handle domain-specific signal by calling appropriate method."""
|
||||||
entity_ids = data[ATTR_ENTITY_ID]
|
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:
|
if entity_ids == ENTITY_MATCH_ALL or self.entity_id in entity_ids:
|
||||||
params = {
|
params = {
|
||||||
key: value
|
key: value
|
||||||
|
|
|
@ -16,6 +16,7 @@ PLATFORM_FORMAT = "{platform}.{domain}"
|
||||||
MATCH_ALL = "*"
|
MATCH_ALL = "*"
|
||||||
|
|
||||||
# Entity target all constant
|
# Entity target all constant
|
||||||
|
ENTITY_MATCH_NONE = "none"
|
||||||
ENTITY_MATCH_ALL = "all"
|
ENTITY_MATCH_ALL = "all"
|
||||||
|
|
||||||
# If no name is specified
|
# If no name is specified
|
||||||
|
|
|
@ -52,6 +52,7 @@ from homeassistant.const import (
|
||||||
CONF_UNIT_SYSTEM_METRIC,
|
CONF_UNIT_SYSTEM_METRIC,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
ENTITY_MATCH_ALL,
|
ENTITY_MATCH_ALL,
|
||||||
|
ENTITY_MATCH_NONE,
|
||||||
SUN_EVENT_SUNRISE,
|
SUN_EVENT_SUNRISE,
|
||||||
SUN_EVENT_SUNSET,
|
SUN_EVENT_SUNSET,
|
||||||
TEMP_CELSIUS,
|
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]
|
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]:
|
def entity_domain(domain: str) -> Callable[[Any], str]:
|
||||||
|
@ -736,7 +739,9 @@ def make_entity_service_schema(
|
||||||
{
|
{
|
||||||
**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.Any(
|
||||||
|
ENTITY_MATCH_NONE, vol.All(ensure_list, [str])
|
||||||
|
),
|
||||||
},
|
},
|
||||||
extra=extra,
|
extra=extra,
|
||||||
),
|
),
|
||||||
|
|
|
@ -7,7 +7,12 @@ from typing import Callable
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.auth.permissions.const import CAT_ENTITIES, POLICY_CONTROL
|
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
|
import homeassistant.core as ha
|
||||||
from homeassistant.exceptions import (
|
from homeassistant.exceptions import (
|
||||||
HomeAssistantError,
|
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)
|
entity_ids = await async_extract_entity_ids(hass, service_call, expand_group)
|
||||||
|
|
||||||
return [
|
found = []
|
||||||
entity
|
|
||||||
for entity in entities
|
for entity in entities:
|
||||||
if entity.available and entity.entity_id in entity_ids
|
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
|
@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)
|
entity_ids = service_call.data.get(ATTR_ENTITY_ID)
|
||||||
area_ids = service_call.data.get(ATTR_AREA_ID)
|
area_ids = service_call.data.get(ATTR_AREA_ID)
|
||||||
|
|
||||||
if not entity_ids and not area_ids:
|
|
||||||
return []
|
|
||||||
|
|
||||||
extracted = set()
|
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
|
# Entity ID attr can be a list or a string
|
||||||
if isinstance(entity_ids, str):
|
if isinstance(entity_ids, str):
|
||||||
entity_ids = [entity_ids]
|
entity_ids = [entity_ids]
|
||||||
|
@ -152,7 +174,7 @@ async def async_extract_entity_ids(hass, service_call, expand_group=True):
|
||||||
|
|
||||||
extracted.update(entity_ids)
|
extracted.update(entity_ids)
|
||||||
|
|
||||||
if area_ids:
|
if area_ids and area_ids != ENTITY_MATCH_NONE:
|
||||||
if isinstance(area_ids, str):
|
if isinstance(area_ids, str):
|
||||||
area_ids = [area_ids]
|
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)
|
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 = [
|
tasks = [
|
||||||
_handle_service_platform_call(
|
_handle_service_platform_call(
|
||||||
hass, func, data, entities, call.context, required_features
|
hass, func, data, entities, call.context, required_features
|
||||||
|
|
|
@ -65,7 +65,10 @@ class TestTTSGooglePlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"google_translate_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -89,7 +92,10 @@ class TestTTSGooglePlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"google_translate_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -115,6 +121,7 @@ class TestTTSGooglePlatform:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"google_say",
|
"google_say",
|
||||||
{
|
{
|
||||||
|
"entity_id": "media_player.something",
|
||||||
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
tts.ATTR_MESSAGE: "90% of I person is on front of your door.",
|
||||||
tts.ATTR_LANGUAGE: "de",
|
tts.ATTR_LANGUAGE: "de",
|
||||||
},
|
},
|
||||||
|
@ -139,7 +146,10 @@ class TestTTSGooglePlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"google_translate_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -161,7 +171,10 @@ class TestTTSGooglePlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"google_translate_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -193,6 +206,7 @@ class TestTTSGooglePlatform:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"google_say",
|
"google_say",
|
||||||
{
|
{
|
||||||
|
"entity_id": "media_player.something",
|
||||||
tts.ATTR_MESSAGE: (
|
tts.ATTR_MESSAGE: (
|
||||||
"I person is on front of your door."
|
"I person is on front of your door."
|
||||||
"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."
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
|
@ -66,7 +66,12 @@ class TestTTSMaryTTSPlatform:
|
||||||
|
|
||||||
with patch("http.client.HTTPConnection", return_value=conn):
|
with patch("http.client.HTTPConnection", return_value=conn):
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -93,7 +98,12 @@ class TestTTSMaryTTSPlatform:
|
||||||
|
|
||||||
with patch("http.client.HTTPConnection", return_value=conn):
|
with patch("http.client.HTTPConnection", return_value=conn):
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -123,7 +133,12 @@ class TestTTSMaryTTSPlatform:
|
||||||
|
|
||||||
with patch("http.client.HTTPConnection", return_value=conn):
|
with patch("http.client.HTTPConnection", return_value=conn):
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
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_TYPE] == MEDIA_TYPE_MUSIC
|
||||||
assert calls[0].data[
|
assert calls[0].data[
|
||||||
ATTR_MEDIA_CONTENT_ID
|
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
|
self.hass.config.api.base_url
|
||||||
)
|
)
|
||||||
assert os.path.isfile(
|
assert os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -125,7 +128,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
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_TYPE] == MEDIA_TYPE_MUSIC
|
||||||
assert calls[0].data[
|
assert calls[0].data[
|
||||||
ATTR_MEDIA_CONTENT_ID
|
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
|
self.hass.config.api.base_url
|
||||||
)
|
)
|
||||||
assert os.path.isfile(
|
assert os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -163,7 +169,8 @@ class TestTTS:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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_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_TYPE] == MEDIA_TYPE_MUSIC
|
||||||
assert calls[0].data[
|
assert calls[0].data[
|
||||||
ATTR_MEDIA_CONTENT_ID
|
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
|
self.hass.config.api.base_url
|
||||||
)
|
)
|
||||||
assert os.path.isfile(
|
assert os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -196,7 +203,8 @@ class TestTTS:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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",
|
tts.ATTR_LANGUAGE: "lang",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -206,7 +214,7 @@ class TestTTS:
|
||||||
assert not os.path.isfile(
|
assert not os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_lang_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_lang_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -223,7 +231,8 @@ class TestTTS:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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_LANGUAGE: "de",
|
||||||
tts.ATTR_OPTIONS: {"voice": "alex"},
|
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_TYPE] == MEDIA_TYPE_MUSIC
|
||||||
assert calls[0].data[
|
assert calls[0].data[
|
||||||
ATTR_MEDIA_CONTENT_ID
|
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
|
self.hass.config.api.base_url, opt_hash
|
||||||
)
|
)
|
||||||
assert os.path.isfile(
|
assert os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_{0}_demo.mp3".format(
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{0}_demo.mp3".format(
|
||||||
opt_hash
|
opt_hash
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -265,7 +274,8 @@ class TestTTS:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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_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_TYPE] == MEDIA_TYPE_MUSIC
|
||||||
assert calls[0].data[
|
assert calls[0].data[
|
||||||
ATTR_MEDIA_CONTENT_ID
|
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
|
self.hass.config.api.base_url, opt_hash
|
||||||
)
|
)
|
||||||
assert os.path.isfile(
|
assert os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_{0}_demo.mp3".format(
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{0}_demo.mp3".format(
|
||||||
opt_hash
|
opt_hash
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -302,7 +312,8 @@ class TestTTS:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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_LANGUAGE: "de",
|
||||||
tts.ATTR_OPTIONS: {"speed": 1},
|
tts.ATTR_OPTIONS: {"speed": 1},
|
||||||
},
|
},
|
||||||
|
@ -315,7 +326,7 @@ class TestTTS:
|
||||||
assert not os.path.isfile(
|
assert not os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_{0}_demo.mp3".format(
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{0}_demo.mp3".format(
|
||||||
opt_hash
|
opt_hash
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -333,7 +344,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
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_TYPE] == MEDIA_TYPE_MUSIC
|
||||||
assert (
|
assert (
|
||||||
calls[0].data[ATTR_MEDIA_CONTENT_ID] == "http://fnord"
|
calls[0].data[ATTR_MEDIA_CONTENT_ID] == "http://fnord"
|
||||||
"/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd"
|
"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||||
"_en_-_demo.mp3"
|
"_en_-_demo.mp3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -357,7 +371,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -365,7 +382,7 @@ class TestTTS:
|
||||||
assert os.path.isfile(
|
assert os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -375,7 +392,7 @@ class TestTTS:
|
||||||
assert not os.path.isfile(
|
assert not os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -393,7 +410,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -401,7 +421,7 @@ class TestTTS:
|
||||||
req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID])
|
req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID])
|
||||||
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
||||||
demo_data = tts.SpeechManager.write_tags(
|
demo_data = tts.SpeechManager.write_tags(
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
demo_data,
|
demo_data,
|
||||||
self.demo_provider,
|
self.demo_provider,
|
||||||
"AI person is in front of your door.",
|
"AI person is in front of your door.",
|
||||||
|
@ -425,7 +445,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -433,10 +456,10 @@ class TestTTS:
|
||||||
req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID])
|
req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID])
|
||||||
_, demo_data = self.demo_provider.get_tts_audio("bla", "de")
|
_, demo_data = self.demo_provider.get_tts_audio("bla", "de")
|
||||||
demo_data = tts.SpeechManager.write_tags(
|
demo_data = tts.SpeechManager.write_tags(
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3",
|
||||||
demo_data,
|
demo_data,
|
||||||
self.demo_provider,
|
self.demo_provider,
|
||||||
"I person is on front of your door.",
|
"There is someone at the door.",
|
||||||
"de",
|
"de",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -453,7 +476,7 @@ class TestTTS:
|
||||||
self.hass.start()
|
self.hass.start()
|
||||||
|
|
||||||
url = (
|
url = (
|
||||||
"{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3"
|
"{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3"
|
||||||
).format(self.hass.config.api.base_url)
|
).format(self.hass.config.api.base_url)
|
||||||
|
|
||||||
req = requests.get(url)
|
req = requests.get(url)
|
||||||
|
@ -487,7 +510,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -495,7 +521,7 @@ class TestTTS:
|
||||||
assert not os.path.isfile(
|
assert not os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -512,7 +538,8 @@ class TestTTS:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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,
|
tts.ATTR_CACHE: False,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -522,7 +549,7 @@ class TestTTS:
|
||||||
assert not os.path.isfile(
|
assert not os.path.isfile(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
self.default_tts_cache,
|
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")
|
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
||||||
cache_file = os.path.join(
|
cache_file = os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
)
|
)
|
||||||
|
|
||||||
os.mkdir(self.default_tts_cache)
|
os.mkdir(self.default_tts_cache)
|
||||||
|
@ -552,14 +579,17 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
assert len(calls) == 1
|
assert len(calls) == 1
|
||||||
assert calls[0].data[
|
assert calls[0].data[
|
||||||
ATTR_MEDIA_CONTENT_ID
|
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
|
self.hass.config.api.base_url
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -579,7 +609,10 @@ class TestTTS:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"demo_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -590,7 +623,7 @@ class TestTTS:
|
||||||
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
_, demo_data = self.demo_provider.get_tts_audio("bla", "en")
|
||||||
cache_file = os.path.join(
|
cache_file = os.path.join(
|
||||||
self.default_tts_cache,
|
self.default_tts_cache,
|
||||||
"265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3",
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3",
|
||||||
)
|
)
|
||||||
|
|
||||||
os.mkdir(self.default_tts_cache)
|
os.mkdir(self.default_tts_cache)
|
||||||
|
@ -605,7 +638,7 @@ class TestTTS:
|
||||||
self.hass.start()
|
self.hass.start()
|
||||||
|
|
||||||
url = (
|
url = (
|
||||||
"{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3"
|
"{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3"
|
||||||
).format(self.hass.config.api.base_url)
|
).format(self.hass.config.api.base_url)
|
||||||
|
|
||||||
req = requests.get(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()
|
client = await hass_client()
|
||||||
|
|
||||||
url = "/api/tts_get_url"
|
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)
|
req = await client.post(url, json=data)
|
||||||
assert req.status == 200
|
assert req.status == 200
|
||||||
response = await req.json()
|
response = await req.json()
|
||||||
assert response.get("url") == (
|
assert response.get("url") == (
|
||||||
"{}/api/tts_proxy/265944c108cbb00b2a62"
|
"{}/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3".format(
|
||||||
"1be5930513e03a0bb2cd_en_-_demo.mp3".format(hass.config.api.base_url)
|
hass.config.api.base_url
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
tts_cache = hass.config.path(tts.DEFAULT_CACHE_DIR)
|
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()
|
client = await hass_client()
|
||||||
|
|
||||||
url = "/api/tts_get_url"
|
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)
|
req = await client.post(url, json=data)
|
||||||
assert req.status == 400
|
assert req.status == 400
|
||||||
|
|
|
@ -67,7 +67,10 @@ class TestTTSVoiceRSSPlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"voicerss_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -97,7 +100,10 @@ class TestTTSVoiceRSSPlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"voicerss_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -121,6 +127,7 @@ class TestTTSVoiceRSSPlatform:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"voicerss_say",
|
"voicerss_say",
|
||||||
{
|
{
|
||||||
|
"entity_id": "media_player.something",
|
||||||
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
tts.ATTR_MESSAGE: "I person is on front of your door.",
|
||||||
tts.ATTR_LANGUAGE: "de-de",
|
tts.ATTR_LANGUAGE: "de-de",
|
||||||
},
|
},
|
||||||
|
@ -145,7 +152,10 @@ class TestTTSVoiceRSSPlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"voicerss_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -167,7 +177,10 @@ class TestTTSVoiceRSSPlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"voicerss_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -194,7 +207,10 @@ class TestTTSVoiceRSSPlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"voicerss_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -103,7 +105,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -135,7 +139,11 @@ class TestTTSYandexPlatform:
|
||||||
self.hass.services.call(
|
self.hass.services.call(
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"yandextts_say",
|
"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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -165,7 +173,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -195,7 +205,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -230,7 +242,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -266,7 +280,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -298,7 +314,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -330,7 +348,9 @@ class TestTTSYandexPlatform:
|
||||||
setup_component(self.hass, tts.DOMAIN, config)
|
setup_component(self.hass, tts.DOMAIN, config)
|
||||||
|
|
||||||
self.hass.services.call(
|
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()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
|
@ -362,6 +382,7 @@ class TestTTSYandexPlatform:
|
||||||
tts.DOMAIN,
|
tts.DOMAIN,
|
||||||
"yandextts_say",
|
"yandextts_say",
|
||||||
{
|
{
|
||||||
|
"entity_id": "media_player.something",
|
||||||
tts.ATTR_MESSAGE: "HomeAssistant",
|
tts.ATTR_MESSAGE: "HomeAssistant",
|
||||||
"options": {"emotion": "evil", "speed": 2},
|
"options": {"emotion": "evil", "speed": 2},
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,8 +7,9 @@ from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import asynctest
|
import asynctest
|
||||||
import pytest
|
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
|
import homeassistant.core as ha
|
||||||
from homeassistant.exceptions import PlatformNotReady
|
from homeassistant.exceptions import PlatformNotReady
|
||||||
from homeassistant.helpers import discovery
|
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")]
|
[MockEntity(name="test_1"), MockEntity(name="test_2")]
|
||||||
)
|
)
|
||||||
|
|
||||||
call = ha.ServiceCall("test", "service")
|
assert (
|
||||||
|
await component.async_extract_from_service(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", {"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 (
|
assert (
|
||||||
"Not passing an entity ID to a service to target all entities is deprecated"
|
"Not passing an entity ID to a service to target all entities is deprecated"
|
||||||
) not in caplog.text
|
) 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 import core as ha, exceptions
|
||||||
from homeassistant.auth.permissions import PolicyPermissions
|
from homeassistant.auth.permissions import PolicyPermissions
|
||||||
import homeassistant.components # noqa: F401
|
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 (
|
from homeassistant.helpers import (
|
||||||
device_registry as dev_reg,
|
device_registry as dev_reg,
|
||||||
entity_registry as ent_reg,
|
entity_registry as ent_reg,
|
||||||
|
@ -252,6 +258,14 @@ async def test_extract_entity_ids(hass):
|
||||||
hass, call, expand_group=False
|
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):
|
async def test_extract_entity_ids_from_area(hass, area_mock):
|
||||||
"""Test extract_entity_ids method with areas."""
|
"""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",
|
"light.diff_area",
|
||||||
} == await service.async_extract_entity_ids(hass, call)
|
} == 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
|
@asyncio.coroutine
|
||||||
def test_async_get_all_descriptions(hass):
|
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))
|
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):
|
async def test_extract_from_service_empty_if_no_entity_id(hass):
|
||||||
"""Test the extraction from service without specifying entity."""
|
"""Test the extraction from service without specifying entity."""
|
||||||
|
|
Loading…
Add table
Reference in a new issue