Example #1
0
def test_create_matcher():
    """Test the create matcher method."""
    # Basic sentence
    pattern = create_matcher("Hello world")
    assert pattern.match("Hello world") is not None

    # Match a part
    pattern = create_matcher("Hello {name}")
    match = pattern.match("hello world")
    assert match is not None
    assert match.groupdict()["name"] == "world"
    no_match = pattern.match("Hello world, how are you?")
    assert no_match is None

    # Optional and matching part
    pattern = create_matcher("Turn on [the] {name}")
    match = pattern.match("turn on the kitchen lights")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen lights"
    match = pattern.match("turn on kitchen lights")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen lights"
    match = pattern.match("turn off kitchen lights")
    assert match is None

    # Two different optional parts, 1 matching part
    pattern = create_matcher("Turn on [the] [a] {name}")
    match = pattern.match("turn on the kitchen lights")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen lights"
    match = pattern.match("turn on kitchen lights")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen lights"
    match = pattern.match("turn on a kitchen light")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen light"

    # Strip plural
    pattern = create_matcher("Turn {name}[s] on")
    match = pattern.match("turn kitchen lights on")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen light"

    # Optional 2 words
    pattern = create_matcher("Turn [the great] {name} on")
    match = pattern.match("turn the great kitchen lights on")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen lights"
    match = pattern.match("turn kitchen lights on")
    assert match is not None
    assert match.groupdict()["name"] == "kitchen lights"
Example #2
0
def async_register(hass, intent_type, utterances):
    """Register utterances and any custom intents.

    Registrations don't require conversations to be loaded. They will become
    active once the conversation component is loaded.
    """
    intents = hass.data.get(DOMAIN)

    if intents is None:
        intents = hass.data[DOMAIN] = {}

    conf = intents.get(intent_type)

    if conf is None:
        conf = intents[intent_type] = []

    for utterance in utterances:
        if isinstance(utterance, REGEX_TYPE):
            conf.append(utterance)
        else:
            conf.append(create_matcher(utterance))
Example #3
0
def async_register(hass, intent_type, utterances):
    """Register utterances and any custom intents.

    Registrations don't require conversations to be loaded. They will become
    active once the conversation component is loaded.
    """
    intents = hass.data.get(DOMAIN)

    if intents is None:
        intents = hass.data[DOMAIN] = {}

    conf = intents.get(intent_type)

    if conf is None:
        conf = intents[intent_type] = []

    for utterance in utterances:
        if isinstance(utterance, REGEX_TYPE):
            conf.append(utterance)
        else:
            conf.append(create_matcher(utterance))
Example #4
0
async def async_setup(hass, config):
    """Set up the Hangouts bot component."""
    config = config.get(DOMAIN)
    if config is None:
        hass.data[DOMAIN] = {
            CONF_INTENTS: {},
            CONF_DEFAULT_CONVERSATIONS: [],
            CONF_ERROR_SUPPRESSED_CONVERSATIONS: [],
        }
        return True

    hass.data[DOMAIN] = {
        CONF_INTENTS: config[CONF_INTENTS],
        CONF_DEFAULT_CONVERSATIONS: config[CONF_DEFAULT_CONVERSATIONS],
        CONF_ERROR_SUPPRESSED_CONVERSATIONS: config[
            CONF_ERROR_SUPPRESSED_CONVERSATIONS
        ],
    }

    if (
        hass.data[DOMAIN][CONF_INTENTS]
        and INTENT_HELP not in hass.data[DOMAIN][CONF_INTENTS]
    ):
        hass.data[DOMAIN][CONF_INTENTS][INTENT_HELP] = {CONF_SENTENCES: ["HELP"]}

    for data in hass.data[DOMAIN][CONF_INTENTS].values():
        matchers = []
        for sentence in data[CONF_SENTENCES]:
            matchers.append(create_matcher(sentence))

        data[CONF_MATCHERS] = matchers

    hass.async_create_task(
        hass.config_entries.flow.async_init(
            DOMAIN, context={"source": config_entries.SOURCE_IMPORT}
        )
    )

    return True
Example #5
0
async def async_setup(hass, config):
    """Register the process service."""
    config = config.get(DOMAIN, {})
    intents = hass.data.get(DOMAIN)

    if intents is None:
        intents = hass.data[DOMAIN] = {}

    for intent_type, utterances in config.get('intents', {}).items():
        conf = intents.get(intent_type)

        if conf is None:
            conf = intents[intent_type] = []

        conf.extend(create_matcher(utterance) for utterance in utterances)

    async def process(service):
        """Parse text into commands."""
        text = service.data[ATTR_TEXT]
        _LOGGER.debug('Processing: <%s>', text)
        try:
            await _process(hass, text)
        except intent.IntentHandleError as err:
            _LOGGER.error('Error processing %s: %s', text, err)

    hass.services.async_register(DOMAIN,
                                 SERVICE_PROCESS,
                                 process,
                                 schema=SERVICE_PROCESS_SCHEMA)

    hass.http.register_view(ConversationProcessView)

    # We strip trailing 's' from name because our state matcher will fail
    # if a letter is not there. By removing 's' we can match singular and
    # plural names.

    async_register(hass, intent.INTENT_TURN_ON, [
        'Turn [the] [a] {name}[s] on',
        'Turn on [the] [a] [an] {name}[s]',
    ])
    async_register(hass, intent.INTENT_TURN_OFF, [
        'Turn [the] [a] [an] {name}[s] off',
        'Turn off [the] [a] [an] {name}[s]',
    ])
    async_register(hass, intent.INTENT_TOGGLE, [
        'Toggle [the] [a] [an] {name}[s]',
        '[the] [a] [an] {name}[s] toggle',
    ])

    @callback
    def register_utterances(component):
        """Register utterances for a component."""
        if component not in UTTERANCES:
            return
        for intent_type, sentences in UTTERANCES[component].items():
            async_register(hass, intent_type, sentences)

    @callback
    def component_loaded(event):
        """Handle a new component loaded."""
        register_utterances(event.data[ATTR_COMPONENT])

    hass.bus.async_listen(EVENT_COMPONENT_LOADED, component_loaded)

    # Check already loaded components.
    for component in hass.config.components:
        register_utterances(component)

    return True
Example #6
0
async def async_setup(hass, config):
    """Register the process service."""
    config = config.get(DOMAIN, {})
    intents = hass.data.get(DOMAIN)

    if intents is None:
        intents = hass.data[DOMAIN] = {}

    for intent_type, utterances in config.get('intents', {}).items():
        conf = intents.get(intent_type)

        if conf is None:
            conf = intents[intent_type] = []

        conf.extend(create_matcher(utterance) for utterance in utterances)

    async def process(service):
        """Parse text into commands."""
        text = service.data[ATTR_TEXT]
        _LOGGER.debug('Processing: <%s>', text)
        try:
            await _process(hass, text)
        except intent.IntentHandleError as err:
            _LOGGER.error('Error processing %s: %s', text, err)

    hass.services.async_register(
        DOMAIN, SERVICE_PROCESS, process, schema=SERVICE_PROCESS_SCHEMA)

    hass.http.register_view(ConversationProcessView)

    # We strip trailing 's' from name because our state matcher will fail
    # if a letter is not there. By removing 's' we can match singular and
    # plural names.

    async_register(hass, intent.INTENT_TURN_ON, [
        'Turn [the] [a] {name}[s] on',
        'Turn on [the] [a] [an] {name}[s]',
    ])
    async_register(hass, intent.INTENT_TURN_OFF, [
        'Turn [the] [a] [an] {name}[s] off',
        'Turn off [the] [a] [an] {name}[s]',
    ])
    async_register(hass, intent.INTENT_TOGGLE, [
        'Toggle [the] [a] [an] {name}[s]',
        '[the] [a] [an] {name}[s] toggle',
    ])

    @callback
    def register_utterances(component):
        """Register utterances for a component."""
        if component not in UTTERANCES:
            return
        for intent_type, sentences in UTTERANCES[component].items():
            async_register(hass, intent_type, sentences)

    @callback
    def component_loaded(event):
        """Handle a new component loaded."""
        register_utterances(event.data[ATTR_COMPONENT])

    hass.bus.async_listen(EVENT_COMPONENT_LOADED, component_loaded)

    # Check already loaded components.
    for component in hass.config.components:
        register_utterances(component)

    return True
        CONF_DEFAULT_CONVERSATIONS:
        conf[CONF_DEFAULT_CONVERSATIONS],
        CONF_ERROR_SUPPRESSED_CONVERSATIONS:
        conf[CONF_ERROR_SUPPRESSED_CONVERSATIONS],
    }

    if (hass.data[DOMAIN][CONF_INTENTS]
            and INTENT_HELP not in hass.data[DOMAIN][CONF_INTENTS]):
        hass.data[DOMAIN][CONF_INTENTS][INTENT_HELP] = {
            CONF_SENTENCES: ["HELP"]
        }

    for data in hass.data[DOMAIN][CONF_INTENTS].values():
        matchers = []
        for sentence in data[CONF_SENTENCES]:
            matchers.append(create_matcher(sentence))

        data[CONF_MATCHERS] = matchers

    hass.async_create_task(
        hass.config_entries.flow.async_init(
            DOMAIN, context={"source": config_entries.SOURCE_IMPORT}))

    return True


async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool:
    """Set up a config entry."""
    try:
        bot = HangoutsBot(
            hass,