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.pypull/8020/head
parent
843f8ce9ee
commit
7fae8cd0f1
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue