Snips sounds (#13746)
* Added feedback sound configuration * Added feedback sound configuration * Cleaned up feedback off * Cleaned up whitespace * Moved feedback pus to helper funx * Async * Used async_mock_service for tests * Lint
This commit is contained in:
parent
c61611d2b4
commit
e593117ab6
2 changed files with 256 additions and 81 deletions
|
@ -4,13 +4,13 @@ Support for Snips on-device ASR and NLU.
|
|||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/snips/
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import intent, config_validation as cv
|
||||
import homeassistant.components.mqtt as mqtt
|
||||
|
||||
|
@ -19,11 +19,18 @@ DEPENDENCIES = ['mqtt']
|
|||
|
||||
CONF_INTENTS = 'intents'
|
||||
CONF_ACTION = 'action'
|
||||
CONF_FEEDBACK = 'feedback_sounds'
|
||||
CONF_PROBABILITY = 'probability_threshold'
|
||||
CONF_SITE_IDS = 'site_ids'
|
||||
|
||||
SERVICE_SAY = 'say'
|
||||
SERVICE_SAY_ACTION = 'say_action'
|
||||
SERVICE_FEEDBACK_ON = 'feedback_on'
|
||||
SERVICE_FEEDBACK_OFF = 'feedback_off'
|
||||
|
||||
INTENT_TOPIC = 'hermes/intent/#'
|
||||
FEEDBACK_ON_TOPIC = 'hermes/feedback/sound/toggleOn'
|
||||
FEEDBACK_OFF_TOPIC = 'hermes/feedback/sound/toggleOff'
|
||||
|
||||
ATTR_TEXT = 'text'
|
||||
ATTR_SITE_ID = 'site_id'
|
||||
|
@ -34,7 +41,12 @@ ATTR_INTENT_FILTER = 'intent_filter'
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: {}
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Optional(CONF_FEEDBACK): cv.boolean,
|
||||
vol.Optional(CONF_PROBABILITY, default=0): vol.Coerce(float),
|
||||
vol.Optional(CONF_SITE_IDS, default=['default']):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
INTENT_SCHEMA = vol.Schema({
|
||||
|
@ -57,7 +69,6 @@ SERVICE_SCHEMA_SAY = vol.Schema({
|
|||
vol.Optional(ATTR_SITE_ID, default='default'): str,
|
||||
vol.Optional(ATTR_CUSTOM_DATA, default=''): str
|
||||
})
|
||||
|
||||
SERVICE_SCHEMA_SAY_ACTION = vol.Schema({
|
||||
vol.Required(ATTR_TEXT): str,
|
||||
vol.Optional(ATTR_SITE_ID, default='default'): str,
|
||||
|
@ -65,13 +76,31 @@ SERVICE_SCHEMA_SAY_ACTION = vol.Schema({
|
|||
vol.Optional(ATTR_CAN_BE_ENQUEUED, default=True): cv.boolean,
|
||||
vol.Optional(ATTR_INTENT_FILTER): vol.All(cv.ensure_list),
|
||||
})
|
||||
SERVICE_SCHEMA_FEEDBACK = vol.Schema({
|
||||
vol.Optional(ATTR_SITE_ID, default='default'): str
|
||||
})
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
async def async_setup(hass, config):
|
||||
"""Activate Snips component."""
|
||||
@asyncio.coroutine
|
||||
def message_received(topic, payload, qos):
|
||||
@callback
|
||||
def async_set_feedback(site_ids, state):
|
||||
"""Set Feedback sound state."""
|
||||
site_ids = (site_ids if site_ids
|
||||
else config[DOMAIN].get(CONF_SITE_IDS))
|
||||
topic = (FEEDBACK_ON_TOPIC if state
|
||||
else FEEDBACK_OFF_TOPIC)
|
||||
for site_id in site_ids:
|
||||
payload = json.dumps({'siteId': site_id})
|
||||
hass.components.mqtt.async_publish(
|
||||
FEEDBACK_ON_TOPIC, None, qos=0, retain=False)
|
||||
hass.components.mqtt.async_publish(
|
||||
topic, payload, qos=int(state), retain=state)
|
||||
|
||||
if CONF_FEEDBACK in config[DOMAIN]:
|
||||
async_set_feedback(None, config[DOMAIN][CONF_FEEDBACK])
|
||||
|
||||
async def message_received(topic, payload, qos):
|
||||
"""Handle new messages on MQTT."""
|
||||
_LOGGER.debug("New intent: %s", payload)
|
||||
|
||||
|
@ -81,6 +110,13 @@ def async_setup(hass, config):
|
|||
_LOGGER.error('Received invalid JSON: %s', payload)
|
||||
return
|
||||
|
||||
if (request['intent']['probability']
|
||||
< config[DOMAIN].get(CONF_PROBABILITY)):
|
||||
_LOGGER.warning("Intent below probaility threshold %s < %s",
|
||||
request['intent']['probability'],
|
||||
config[DOMAIN].get(CONF_PROBABILITY))
|
||||
return
|
||||
|
||||
try:
|
||||
request = INTENT_SCHEMA(request)
|
||||
except vol.Invalid as err:
|
||||
|
@ -97,7 +133,7 @@ def async_setup(hass, config):
|
|||
slots[slot['slotName']] = {'value': resolve_slot_values(slot)}
|
||||
|
||||
try:
|
||||
intent_response = yield from intent.async_handle(
|
||||
intent_response = await intent.async_handle(
|
||||
hass, DOMAIN, intent_type, slots, request['input'])
|
||||
if 'plain' in intent_response.speech:
|
||||
snips_response = intent_response.speech['plain']['speech']
|
||||
|
@ -115,11 +151,10 @@ def async_setup(hass, config):
|
|||
mqtt.async_publish(hass, 'hermes/dialogueManager/endSession',
|
||||
json.dumps(notification))
|
||||
|
||||
yield from hass.components.mqtt.async_subscribe(
|
||||
await hass.components.mqtt.async_subscribe(
|
||||
INTENT_TOPIC, message_received)
|
||||
|
||||
@asyncio.coroutine
|
||||
def snips_say(call):
|
||||
async def snips_say(call):
|
||||
"""Send a Snips notification message."""
|
||||
notification = {'siteId': call.data.get(ATTR_SITE_ID, 'default'),
|
||||
'customData': call.data.get(ATTR_CUSTOM_DATA, ''),
|
||||
|
@ -129,8 +164,7 @@ def async_setup(hass, config):
|
|||
json.dumps(notification))
|
||||
return
|
||||
|
||||
@asyncio.coroutine
|
||||
def snips_say_action(call):
|
||||
async def snips_say_action(call):
|
||||
"""Send a Snips action message."""
|
||||
notification = {'siteId': call.data.get(ATTR_SITE_ID, 'default'),
|
||||
'customData': call.data.get(ATTR_CUSTOM_DATA, ''),
|
||||
|
@ -144,12 +178,26 @@ def async_setup(hass, config):
|
|||
json.dumps(notification))
|
||||
return
|
||||
|
||||
async def feedback_on(call):
|
||||
"""Turn feedback sounds on."""
|
||||
async_set_feedback(call.data.get(ATTR_SITE_ID), True)
|
||||
|
||||
async def feedback_off(call):
|
||||
"""Turn feedback sounds off."""
|
||||
async_set_feedback(call.data.get(ATTR_SITE_ID), False)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_SAY, snips_say,
|
||||
schema=SERVICE_SCHEMA_SAY)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_SAY_ACTION, snips_say_action,
|
||||
schema=SERVICE_SCHEMA_SAY_ACTION)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_FEEDBACK_ON, feedback_on,
|
||||
schema=SERVICE_SCHEMA_FEEDBACK)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_FEEDBACK_OFF, feedback_off,
|
||||
schema=SERVICE_SCHEMA_FEEDBACK)
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -1,20 +1,92 @@
|
|||
"""Test the Snips component."""
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.bootstrap import async_setup_component
|
||||
from homeassistant.components.mqtt import MQTT_PUBLISH_SCHEMA
|
||||
import homeassistant.components.snips as snips
|
||||
from tests.common import (async_fire_mqtt_message, async_mock_intent,
|
||||
async_mock_service)
|
||||
from homeassistant.components.snips import (SERVICE_SCHEMA_SAY,
|
||||
SERVICE_SCHEMA_SAY_ACTION)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_intent(hass, mqtt_mock):
|
||||
async def test_snips_config(hass, mqtt_mock):
|
||||
"""Test Snips Config."""
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {
|
||||
"feedback_sounds": True,
|
||||
"probability_threshold": .5,
|
||||
"site_ids": ["default", "remote"]
|
||||
},
|
||||
})
|
||||
assert result
|
||||
|
||||
|
||||
async def test_snips_bad_config(hass, mqtt_mock):
|
||||
"""Test Snips bad config."""
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {
|
||||
"feedback_sounds": "on",
|
||||
"probability": "none",
|
||||
"site_ids": "default"
|
||||
},
|
||||
})
|
||||
assert not result
|
||||
|
||||
|
||||
async def test_snips_config_feedback_on(hass, mqtt_mock):
|
||||
"""Test Snips Config."""
|
||||
calls = async_mock_service(hass, 'mqtt', 'publish', MQTT_PUBLISH_SCHEMA)
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {
|
||||
"feedback_sounds": True
|
||||
},
|
||||
})
|
||||
assert result
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 2
|
||||
topic = calls[0].data['topic']
|
||||
assert topic == 'hermes/feedback/sound/toggleOn'
|
||||
topic = calls[1].data['topic']
|
||||
assert topic == 'hermes/feedback/sound/toggleOn'
|
||||
assert calls[1].data['qos'] == 1
|
||||
assert calls[1].data['retain']
|
||||
|
||||
|
||||
async def test_snips_config_feedback_off(hass, mqtt_mock):
|
||||
"""Test Snips Config."""
|
||||
calls = async_mock_service(hass, 'mqtt', 'publish', MQTT_PUBLISH_SCHEMA)
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {
|
||||
"feedback_sounds": False
|
||||
},
|
||||
})
|
||||
assert result
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 2
|
||||
topic = calls[0].data['topic']
|
||||
assert topic == 'hermes/feedback/sound/toggleOn'
|
||||
topic = calls[1].data['topic']
|
||||
assert topic == 'hermes/feedback/sound/toggleOff'
|
||||
assert calls[1].data['qos'] == 0
|
||||
assert not calls[1].data['retain']
|
||||
|
||||
|
||||
async def test_snips_config_no_feedback(hass, mqtt_mock):
|
||||
"""Test Snips Config."""
|
||||
calls = async_mock_service(hass, 'snips', 'say')
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 0
|
||||
|
||||
|
||||
async def test_snips_intent(hass, mqtt_mock):
|
||||
"""Test intent via Snips."""
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
|
@ -41,7 +113,7 @@ def test_snips_intent(hass, mqtt_mock):
|
|||
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/Lights',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert len(intents) == 1
|
||||
intent = intents[0]
|
||||
assert intent.platform == 'snips'
|
||||
|
@ -50,10 +122,9 @@ def test_snips_intent(hass, mqtt_mock):
|
|||
assert intent.text_input == 'turn the lights green'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_intent_with_duration(hass, mqtt_mock):
|
||||
async def test_snips_intent_with_duration(hass, mqtt_mock):
|
||||
"""Test intent with Snips duration."""
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
|
@ -61,7 +132,8 @@ def test_snips_intent_with_duration(hass, mqtt_mock):
|
|||
{
|
||||
"input": "set a timer of five minutes",
|
||||
"intent": {
|
||||
"intentName": "SetTimer"
|
||||
"intentName": "SetTimer",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": [
|
||||
{
|
||||
|
@ -92,7 +164,7 @@ def test_snips_intent_with_duration(hass, mqtt_mock):
|
|||
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/SetTimer',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert len(intents) == 1
|
||||
intent = intents[0]
|
||||
assert intent.platform == 'snips'
|
||||
|
@ -100,22 +172,14 @@ def test_snips_intent_with_duration(hass, mqtt_mock):
|
|||
assert intent.slots == {'timer_duration': {'value': 300}}
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_intent_speech_response(hass, mqtt_mock):
|
||||
async def test_intent_speech_response(hass, mqtt_mock):
|
||||
"""Test intent speech response via Snips."""
|
||||
event = 'call_service'
|
||||
events = []
|
||||
|
||||
@callback
|
||||
def record_event(event):
|
||||
"""Add recorded event to set."""
|
||||
events.append(event)
|
||||
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
calls = async_mock_service(hass, 'mqtt', 'publish', MQTT_PUBLISH_SCHEMA)
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
result = yield from async_setup_component(hass, "intent_script", {
|
||||
result = await async_setup_component(hass, "intent_script", {
|
||||
"intent_script": {
|
||||
"spokenIntent": {
|
||||
"speech": {
|
||||
|
@ -131,31 +195,28 @@ def test_intent_speech_response(hass, mqtt_mock):
|
|||
"input": "speak to me",
|
||||
"sessionId": "abcdef0123456789",
|
||||
"intent": {
|
||||
"intentName": "spokenIntent"
|
||||
"intentName": "spokenIntent",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
"""
|
||||
hass.bus.async_listen(event, record_event)
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/spokenIntent',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(events) == 1
|
||||
assert events[0].data['domain'] == 'mqtt'
|
||||
assert events[0].data['service'] == 'publish'
|
||||
payload = json.loads(events[0].data['service_data']['payload'])
|
||||
topic = events[0].data['service_data']['topic']
|
||||
assert len(calls) == 1
|
||||
payload = json.loads(calls[0].data['payload'])
|
||||
topic = calls[0].data['topic']
|
||||
assert payload['sessionId'] == 'abcdef0123456789'
|
||||
assert payload['text'] == 'I am speaking to you'
|
||||
assert topic == 'hermes/dialogueManager/endSession'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_unknown_intent(hass, mqtt_mock, caplog):
|
||||
async def test_unknown_intent(hass, mqtt_mock, caplog):
|
||||
"""Test unknown intent."""
|
||||
caplog.set_level(logging.WARNING)
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
|
@ -164,21 +225,21 @@ def test_unknown_intent(hass, mqtt_mock, caplog):
|
|||
"input": "I don't know what I am supposed to do",
|
||||
"sessionId": "abcdef1234567890",
|
||||
"intent": {
|
||||
"intentName": "unknownIntent"
|
||||
"intentName": "unknownIntent",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
"""
|
||||
async_fire_mqtt_message(hass,
|
||||
'hermes/intent/unknownIntent', payload)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert 'Received unknown intent unknownIntent' in caplog.text
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_intent_user(hass, mqtt_mock):
|
||||
async def test_snips_intent_user(hass, mqtt_mock):
|
||||
"""Test intentName format user_XXX__intentName."""
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
|
@ -186,7 +247,8 @@ def test_snips_intent_user(hass, mqtt_mock):
|
|||
{
|
||||
"input": "what to do",
|
||||
"intent": {
|
||||
"intentName": "user_ABCDEF123__Lights"
|
||||
"intentName": "user_ABCDEF123__Lights",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
|
@ -194,7 +256,7 @@ def test_snips_intent_user(hass, mqtt_mock):
|
|||
intents = async_mock_intent(hass, 'Lights')
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/user_ABCDEF123__Lights',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(intents) == 1
|
||||
intent = intents[0]
|
||||
|
@ -202,10 +264,9 @@ def test_snips_intent_user(hass, mqtt_mock):
|
|||
assert intent.intent_type == 'Lights'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_intent_username(hass, mqtt_mock):
|
||||
async def test_snips_intent_username(hass, mqtt_mock):
|
||||
"""Test intentName format username:intentName."""
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
|
@ -213,7 +274,8 @@ def test_snips_intent_username(hass, mqtt_mock):
|
|||
{
|
||||
"input": "what to do",
|
||||
"intent": {
|
||||
"intentName": "username:Lights"
|
||||
"intentName": "username:Lights",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
|
@ -221,7 +283,7 @@ def test_snips_intent_username(hass, mqtt_mock):
|
|||
intents = async_mock_intent(hass, 'Lights')
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/username:Lights',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(intents) == 1
|
||||
intent = intents[0]
|
||||
|
@ -229,15 +291,41 @@ def test_snips_intent_username(hass, mqtt_mock):
|
|||
assert intent.intent_type == 'Lights'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_say(hass, caplog):
|
||||
async def test_snips_low_probability(hass, mqtt_mock, caplog):
|
||||
"""Test intent via Snips."""
|
||||
caplog.set_level(logging.WARNING)
|
||||
result = await async_setup_component(hass, "snips", {
|
||||
"snips": {
|
||||
"probability_threshold": 0.5
|
||||
},
|
||||
})
|
||||
assert result
|
||||
payload = """
|
||||
{
|
||||
"input": "I am not sure what to say",
|
||||
"intent": {
|
||||
"intentName": "LightsMaybe",
|
||||
"probability": 0.49
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
"""
|
||||
|
||||
async_mock_intent(hass, 'LightsMaybe')
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/LightsMaybe',
|
||||
payload)
|
||||
await hass.async_block_till_done()
|
||||
assert 'Intent below probaility threshold 0.49 < 0.5' in caplog.text
|
||||
|
||||
|
||||
async def test_snips_say(hass, caplog):
|
||||
"""Test snips say with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'say',
|
||||
SERVICE_SCHEMA_SAY)
|
||||
snips.SERVICE_SCHEMA_SAY)
|
||||
|
||||
data = {'text': 'Hello'}
|
||||
yield from hass.services.async_call('snips', 'say', data)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.services.async_call('snips', 'say', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].domain == 'snips'
|
||||
|
@ -245,15 +333,14 @@ def test_snips_say(hass, caplog):
|
|||
assert calls[0].data['text'] == 'Hello'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_say_action(hass, caplog):
|
||||
async def test_snips_say_action(hass, caplog):
|
||||
"""Test snips say_action with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'say_action',
|
||||
SERVICE_SCHEMA_SAY_ACTION)
|
||||
snips.SERVICE_SCHEMA_SAY_ACTION)
|
||||
|
||||
data = {'text': 'Hello', 'intent_filter': ['myIntent']}
|
||||
yield from hass.services.async_call('snips', 'say_action', data)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.services.async_call('snips', 'say_action', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].domain == 'snips'
|
||||
|
@ -262,31 +349,71 @@ def test_snips_say_action(hass, caplog):
|
|||
assert calls[0].data['intent_filter'] == ['myIntent']
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_say_invalid_config(hass, caplog):
|
||||
async def test_snips_say_invalid_config(hass, caplog):
|
||||
"""Test snips say with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'say',
|
||||
SERVICE_SCHEMA_SAY)
|
||||
snips.SERVICE_SCHEMA_SAY)
|
||||
|
||||
data = {'text': 'Hello', 'badKey': 'boo'}
|
||||
yield from hass.services.async_call('snips', 'say', data)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.services.async_call('snips', 'say', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 0
|
||||
assert 'ERROR' in caplog.text
|
||||
assert 'Invalid service data' in caplog.text
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_say_action_invalid_config(hass, caplog):
|
||||
async def test_snips_say_action_invalid(hass, caplog):
|
||||
"""Test snips say_action with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'say_action',
|
||||
SERVICE_SCHEMA_SAY_ACTION)
|
||||
snips.SERVICE_SCHEMA_SAY_ACTION)
|
||||
|
||||
data = {'text': 'Hello', 'can_be_enqueued': 'notabool'}
|
||||
yield from hass.services.async_call('snips', 'say_action', data)
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.services.async_call('snips', 'say_action', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 0
|
||||
assert 'ERROR' in caplog.text
|
||||
assert 'Invalid service data' in caplog.text
|
||||
|
||||
|
||||
async def test_snips_feedback_on(hass, caplog):
|
||||
"""Test snips say with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'feedback_on',
|
||||
snips.SERVICE_SCHEMA_FEEDBACK)
|
||||
|
||||
data = {'site_id': 'remote'}
|
||||
await hass.services.async_call('snips', 'feedback_on', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].domain == 'snips'
|
||||
assert calls[0].service == 'feedback_on'
|
||||
assert calls[0].data['site_id'] == 'remote'
|
||||
|
||||
|
||||
async def test_snips_feedback_off(hass, caplog):
|
||||
"""Test snips say with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'feedback_off',
|
||||
snips.SERVICE_SCHEMA_FEEDBACK)
|
||||
|
||||
data = {'site_id': 'remote'}
|
||||
await hass.services.async_call('snips', 'feedback_off', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].domain == 'snips'
|
||||
assert calls[0].service == 'feedback_off'
|
||||
assert calls[0].data['site_id'] == 'remote'
|
||||
|
||||
|
||||
async def test_snips_feedback_config(hass, caplog):
|
||||
"""Test snips say with invalid config."""
|
||||
calls = async_mock_service(hass, 'snips', 'feedback_on',
|
||||
snips.SERVICE_SCHEMA_FEEDBACK)
|
||||
|
||||
data = {'site_id': 'remote', 'test': 'test'}
|
||||
await hass.services.async_call('snips', 'feedback_on', data)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 0
|
||||
|
|
Loading…
Add table
Reference in a new issue