Snips add say and say_actions services (new) (#11596)

* Added snips.say and snips.say_action services

* Added snips.say and snips.say_action services

* Merged services.yaml changes I missed

* added tests for new service configs

* Woof

* Woof Woof

* Changed attribute names to follow hass standards.

* updated test_snips with new attribute names
pull/11589/head
tschmidty69 2018-01-12 13:19:43 -05:00 committed by Fabian Affolter
parent b8dfa4c3d2
commit 179d99381d
No known key found for this signature in database
GPG Key ID: DDF3D6F44AAB1336
3 changed files with 158 additions and 1 deletions

View File

@ -364,6 +364,38 @@ abode:
description: Entity id of the quick action to trigger.
example: 'binary_sensor.home_quick_action'
snips:
say:
description: Send a TTS message to Snips.
fields:
text:
description: Text to say.
example: My name is snips
site_id:
description: Site to use to start session, defaults to default (optional)
example: bedroom
custom_data:
description: custom data that will be included with all messages in this session
example: user=UserName
say_action:
description: Send a TTS message to Snips to listen for a response.
fields:
text:
description: Text to say
example: My name is snips
site_id:
description: Site to use to start session, defaults to default (optional)
example: bedroom
custom_data:
description: custom data that will be included with all messages in this session
example: user=UserName
can_be_enqueued:
description: If True, session waits for an open session to end, if False session is dropped if one is running
example: True
intent_filter:
description: Optional Array of Strings - A list of intents names to restrict the NLU resolution to on the first query.
example: turnOnLights, turnOffLights
input_boolean:
toggle:
description: Toggles an input boolean.

View File

@ -8,17 +8,29 @@ import asyncio
import json
import logging
from datetime import timedelta
import voluptuous as vol
from homeassistant.helpers import intent, config_validation as cv
import homeassistant.components.mqtt as mqtt
DOMAIN = 'snips'
DEPENDENCIES = ['mqtt']
CONF_INTENTS = 'intents'
CONF_ACTION = 'action'
SERVICE_SAY = 'say'
SERVICE_SAY_ACTION = 'say_action'
INTENT_TOPIC = 'hermes/intent/#'
ATTR_TEXT = 'text'
ATTR_SITE_ID = 'site_id'
ATTR_CUSTOM_DATA = 'custom_data'
ATTR_CAN_BE_ENQUEUED = 'can_be_enqueued'
ATTR_INTENT_FILTER = 'intent_filter'
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema({
@ -40,6 +52,20 @@ INTENT_SCHEMA = vol.Schema({
}]
}, extra=vol.ALLOW_EXTRA)
SERVICE_SCHEMA_SAY = vol.Schema({
vol.Required(ATTR_TEXT): str,
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,
vol.Optional(ATTR_CUSTOM_DATA, default=''): str,
vol.Optional(ATTR_CAN_BE_ENQUEUED, default=True): cv.boolean,
vol.Optional(ATTR_INTENT_FILTER): vol.All(cv.ensure_list),
})
@asyncio.coroutine
def async_setup(hass, config):
@ -93,6 +119,39 @@ def async_setup(hass, config):
yield from hass.components.mqtt.async_subscribe(
INTENT_TOPIC, message_received)
@asyncio.coroutine
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, ''),
'init': {'type': 'notification',
'text': call.data.get(ATTR_TEXT)}}
mqtt.async_publish(hass, 'hermes/dialogueManager/startSession',
json.dumps(notification))
return
@asyncio.coroutine
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, ''),
'init': {'type': 'action',
'text': call.data.get(ATTR_TEXT),
'canBeEnqueued': call.data.get(
ATTR_CAN_BE_ENQUEUED, True),
'intentFilter':
call.data.get(ATTR_INTENT_FILTER, [])}}
mqtt.async_publish(hass, 'hermes/dialogueManager/startSession',
json.dumps(notification))
return
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)
return True

View File

@ -4,7 +4,10 @@ import json
from homeassistant.core import callback
from homeassistant.bootstrap import async_setup_component
from tests.common import async_fire_mqtt_message, async_mock_intent
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
@ -238,3 +241,66 @@ def test_snips_intent_username(hass, mqtt_mock):
intent = intents[0]
assert intent.platform == 'snips'
assert intent.intent_type == 'Lights'
@asyncio.coroutine
def test_snips_say(hass, caplog):
"""Test snips say with invalid config."""
calls = async_mock_service(hass, 'snips', 'say',
SERVICE_SCHEMA_SAY)
data = {'text': 'Hello'}
yield from hass.services.async_call('snips', 'say', data)
yield from hass.async_block_till_done()
assert len(calls) == 1
assert calls[0].domain == 'snips'
assert calls[0].service == 'say'
assert calls[0].data['text'] == 'Hello'
@asyncio.coroutine
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)
data = {'text': 'Hello', 'intent_filter': ['myIntent']}
yield from hass.services.async_call('snips', 'say_action', data)
yield from hass.async_block_till_done()
assert len(calls) == 1
assert calls[0].domain == 'snips'
assert calls[0].service == 'say_action'
assert calls[0].data['text'] == 'Hello'
assert calls[0].data['intent_filter'] == ['myIntent']
@asyncio.coroutine
def test_snips_say_invalid_config(hass, caplog):
"""Test snips say with invalid config."""
calls = async_mock_service(hass, 'snips', 'say',
SERVICE_SCHEMA_SAY)
data = {'text': 'Hello', 'badKey': 'boo'}
yield from hass.services.async_call('snips', 'say', data)
yield from 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):
"""Test snips say_action with invalid config."""
calls = async_mock_service(hass, 'snips', 'say_action',
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()
assert len(calls) == 0
assert 'ERROR' in caplog.text
assert 'Invalid service data' in caplog.text