Configure conversation for custom actions with keywords (#7734)

* - Simple keyword to action config

* - Added more fuzzy stuff

* - Logging & a bit of commenting

* - pep8?

* - pep8 and quick formatting fixes

* - Changed configuration a bit

* - Backwards compatibility tests

* - Fallback or

* - Added custom configuration for conversation

* - Moved imports inside function

* - pep8

* - Pass tests better

* - Removed unused imports

* - Moved warning ignore to above import for fuzzy

* - Moved return for consistent return types

* - Fallback if no choices to listen for

* - Fixed linting errors

* - Better logging and fixed linting errors(?)

* - Fixed continuation

* - Added one blank line after class docstring

* Create conversation.py

* Create test_conversation.py

* Create test_conversation.py

* Update test_conversation.py
pull/8020/head
Marco Sirabella 2017-06-13 02:34:20 -04:00 committed by Paulus Schoutsen
parent 843f8ce9ee
commit 7fae8cd0f1
2 changed files with 73 additions and 4 deletions

View File

@ -14,11 +14,13 @@ from homeassistant import core
from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import script
REQUIREMENTS = ['fuzzywuzzy==0.15.0']
ATTR_TEXT = 'text'
ATTR_SENTENCE = 'sentence'
DOMAIN = 'conversation'
REGEX_TURN_COMMAND = re.compile(r'turn (?P<name>(?: |\w)+) (?P<command>\w+)')
@ -29,9 +31,12 @@ SERVICE_PROCESS_SCHEMA = vol.Schema({
vol.Required(ATTR_TEXT): vol.All(cv.string, vol.Lower),
})
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({}),
}, extra=vol.ALLOW_EXTRA)
CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({
cv.string: vol.Schema({
vol.Required(ATTR_SENTENCE): cv.string,
vol.Required('action'): cv.SCRIPT_SCHEMA,
})
})}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
@ -40,9 +45,30 @@ def setup(hass, config):
from fuzzywuzzy import process as fuzzyExtract
logger = logging.getLogger(__name__)
config = config.get(DOMAIN, {})
choices = {attrs[ATTR_SENTENCE]: script.Script(
hass,
attrs['action'],
name)
for name, attrs in config.items()}
def process(service):
"""Parse text into commands."""
# if actually configured
if choices:
text = service.data[ATTR_TEXT]
match = fuzzyExtract.extractOne(text, choices.keys())
scorelimit = 60 # arbitrary value
logging.info(
'matched up text %s and found %s',
text,
[match[0] if match[1] > scorelimit else 'nothing']
)
if match[1] > scorelimit:
choices[match[0]].run() # run respective script
return
text = service.data[ATTR_TEXT]
match = REGEX_TURN_COMMAND.match(text)

View File

@ -117,3 +117,46 @@ class TestConversation(unittest.TestCase):
conversation.DOMAIN, 'process', event_data, True))
self.assertTrue(mock_logger.called)
self.assertFalse(mock_call.called)
class TestConfiguration(unittest.TestCase):
"""Test the conversation configuration component."""
# pylint: disable=invalid-name
def setUp(self):
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.assertTrue(setup_component(self.hass, conversation.DOMAIN, {
conversation.DOMAIN: {
'test_2': {
'sentence': 'switch boolean',
'action': {
'service': 'input_boolean.toggle'
}
}
}
}))
# pylint: disable=invalid-name
def tearDown(self):
"""Stop everything that was started."""
self.hass.stop()
def test_custom(self):
"""Setup and perform good turn on requests."""
calls = []
@callback
def record_call(service):
"""Recorder for a call."""
calls.append(service)
self.hass.services.register('input_boolean', 'toggle', record_call)
event_data = {conversation.ATTR_TEXT: 'switch boolean'}
self.assertTrue(self.hass.services.call(
conversation.DOMAIN, 'process', event_data, True))
call = calls[-1]
self.assertEqual('input_boolean', call.domain)
self.assertEqual('toggle', call.service)