예제 #1
0
def test_deprecated_api_clear_completed(hass, hass_client, sl_setup):
    """Test the API."""

    yield from intent.async_handle(hass, "test", "HassShoppingListAddItem",
                                   {"item": {
                                       "value": "beer"
                                   }})
    yield from intent.async_handle(hass, "test", "HassShoppingListAddItem",
                                   {"item": {
                                       "value": "wine"
                                   }})

    beer_id = hass.data["shopping_list"].items[0]["id"]
    wine_id = hass.data["shopping_list"].items[1]["id"]

    client = yield from hass_client()

    # Mark beer as completed
    resp = yield from client.post("/api/shopping_list/item/{}".format(beer_id),
                                  json={"complete": True})
    assert resp.status == 200

    resp = yield from client.post("/api/shopping_list/clear_completed")
    assert resp.status == 200

    items = hass.data["shopping_list"].items
    assert len(items) == 1

    assert items[0] == {"id": wine_id, "name": "wine", "complete": False}
예제 #2
0
def test_deprecated_api_update(hass, hass_client, sl_setup):
    """Test the API."""

    yield from intent.async_handle(hass, "test", "HassShoppingListAddItem",
                                   {"item": {
                                       "value": "beer"
                                   }})
    yield from intent.async_handle(hass, "test", "HassShoppingListAddItem",
                                   {"item": {
                                       "value": "wine"
                                   }})

    beer_id = hass.data["shopping_list"].items[0]["id"]
    wine_id = hass.data["shopping_list"].items[1]["id"]

    client = yield from hass_client()
    resp = yield from client.post("/api/shopping_list/item/{}".format(beer_id),
                                  json={"name": "soda"})

    assert resp.status == 200
    data = yield from resp.json()
    assert data == {"id": beer_id, "name": "soda", "complete": False}

    resp = yield from client.post("/api/shopping_list/item/{}".format(wine_id),
                                  json={"complete": True})

    assert resp.status == 200
    data = yield from resp.json()
    assert data == {"id": wine_id, "name": "wine", "complete": True}

    beer, wine = hass.data["shopping_list"].items
    assert beer == {"id": beer_id, "name": "soda", "complete": False}
    assert wine == {"id": wine_id, "name": "wine", "complete": True}
예제 #3
0
def test_api_clear_completed(hass, test_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )

    beer_id = hass.data['shopping_list'].items[0]['id']
    wine_id = hass.data['shopping_list'].items[1]['id']

    client = yield from test_client(hass.http.app)

    # Mark beer as completed
    resp = yield from client.post(
        '/api/shopping_list/item/{}'.format(beer_id), json={
            'complete': True
        })
    assert resp.status == 200

    resp = yield from client.post('/api/shopping_list/clear_completed')
    assert resp.status == 200

    items = hass.data['shopping_list'].items
    assert len(items) == 1

    assert items[0] == {
        'id': wine_id,
        'name': 'wine',
        'complete': False
    }
def test_api_clear_completed(hass, test_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )

    beer_id = hass.data['shopping_list'].items[0]['id']
    wine_id = hass.data['shopping_list'].items[1]['id']

    client = yield from test_client(hass.http.app)

    # Mark beer as completed
    resp = yield from client.post(
        '/api/shopping_list/item/{}'.format(beer_id), json={
            'complete': True
        })
    assert resp.status == 200

    resp = yield from client.post('/api/shopping_list/clear_completed')
    assert resp.status == 200

    items = hass.data['shopping_list'].items
    assert len(items) == 1

    assert items[0] == {
        'id': wine_id,
        'name': 'wine',
        'complete': False
    }
예제 #5
0
def test_deprecated_api_update(hass, hass_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(hass, 'test', 'HassShoppingListAddItem',
                                   {'item': {
                                       'value': 'beer'
                                   }})
    yield from intent.async_handle(hass, 'test', 'HassShoppingListAddItem',
                                   {'item': {
                                       'value': 'wine'
                                   }})

    beer_id = hass.data['shopping_list'].items[0]['id']
    wine_id = hass.data['shopping_list'].items[1]['id']

    client = yield from hass_client()
    resp = yield from client.post('/api/shopping_list/item/{}'.format(beer_id),
                                  json={'name': 'soda'})

    assert resp.status == 200
    data = yield from resp.json()
    assert data == {'id': beer_id, 'name': 'soda', 'complete': False}

    resp = yield from client.post('/api/shopping_list/item/{}'.format(wine_id),
                                  json={'complete': True})

    assert resp.status == 200
    data = yield from resp.json()
    assert data == {'id': wine_id, 'name': 'wine', 'complete': True}

    beer, wine = hass.data['shopping_list'].items
    assert beer == {'id': beer_id, 'name': 'soda', 'complete': False}
    assert wine == {'id': wine_id, 'name': 'wine', 'complete': True}
def test_api_update(hass, test_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )

    beer_id = hass.data['shopping_list'].items[0]['id']
    wine_id = hass.data['shopping_list'].items[1]['id']

    client = yield from test_client(hass.http.app)
    resp = yield from client.post(
        '/api/shopping_list/item/{}'.format(beer_id), json={
            'name': 'soda'
        })

    assert resp.status == 200
    data = yield from resp.json()
    assert data == {
        'id': beer_id,
        'name': 'soda',
        'complete': False
    }

    resp = yield from client.post(
        '/api/shopping_list/item/{}'.format(wine_id), json={
            'complete': True
        })

    assert resp.status == 200
    data = yield from resp.json()
    assert data == {
        'id': wine_id,
        'name': 'wine',
        'complete': True
    }

    beer, wine = hass.data['shopping_list'].items
    assert beer == {
        'id': beer_id,
        'name': 'soda',
        'complete': False
    }
    assert wine == {
        'id': wine_id,
        'name': 'wine',
        'complete': True
    }
예제 #7
0
    def message_received(topic, payload, qos):
        """Handle new messages on MQTT."""
        _LOGGER.debug("New intent: %s", payload)

        try:
            request = json.loads(payload)
        except TypeError:
            _LOGGER.error('Received invalid JSON: %s', payload)
            return

        try:
            request = INTENT_SCHEMA(request)
        except vol.Invalid as err:
            _LOGGER.error('Intent has invalid schema: %s. %s', err, request)
            return

        intent_type = request['intent']['intentName'].split('__')[-1]
        slots = {slot['slotName']: {'value': slot['value']['value']}
                 for slot in request.get('slots', [])}

        try:
            yield from intent.async_handle(
                hass, DOMAIN, intent_type, slots, request['input'])
        except intent.IntentError:
            _LOGGER.exception("Error while handling intent: %s.", intent_type)
def test_intent_script(hass):
    """Test intent scripts work."""
    calls = async_mock_service(hass, 'test', 'service')

    yield from async_setup_component(hass, 'intent_script', {
        'intent_script': {
            'HelloWorld': {
                'action': {
                    'service': 'test.service',
                    'data_template': {
                        'hello': '{{ name }}'
                    }
                },
                'card': {
                    'title': 'Hello {{ name }}',
                    'content': 'Content for {{ name }}',
                },
                'speech': {
                    'text': 'Good morning {{ name }}'
                }
            }
        }
    })

    response = yield from intent.async_handle(
        hass, 'test', 'HelloWorld', {'name': {'value': 'Paulus'}}
    )

    assert len(calls) == 1
    assert calls[0].data['hello'] == 'Paulus'

    assert response.speech['plain']['speech'] == 'Good morning Paulus'

    assert response.card['simple']['title'] == 'Hello Paulus'
    assert response.card['simple']['content'] == 'Content for Paulus'
예제 #9
0
def test_turn_on_multiple_intent(hass):
    """Test HassTurnOn intent with multiple similar entities.

    This tests that matching finds the proper entity among similar names.
    """
    result = yield from comps.async_setup(hass, {})
    assert result

    hass.states.async_set('light.test_light', 'off')
    hass.states.async_set('light.test_lights_2', 'off')
    hass.states.async_set('light.test_lighter', 'off')
    calls = async_mock_service(hass, 'light', SERVICE_TURN_ON)

    response = yield from intent.async_handle(
        hass, 'test', 'HassTurnOn', {'name': {
            'value': 'test lights'
        }})
    yield from hass.async_block_till_done()

    assert response.speech['plain']['speech'] == 'Turned test lights 2 on'
    assert len(calls) == 1
    call = calls[0]
    assert call.domain == 'light'
    assert call.service == 'turn_on'
    assert call.data == {'entity_id': ['light.test_lights_2']}
예제 #10
0
    def message_received(topic, payload, qos):
        """Handle new messages on MQTT."""
        _LOGGER.debug("New intent: %s", payload)

        try:
            request = json.loads(payload)
        except TypeError:
            _LOGGER.error('Received invalid JSON: %s', payload)
            return

        try:
            request = INTENT_SCHEMA(request)
        except vol.Invalid as err:
            _LOGGER.error('Intent has invalid schema: %s. %s', err, request)
            return

        intent_type = request['intent']['intentName'].split('__')[-1]
        slots = {
            slot['slotName']: {
                'value': slot['value']['value']
            }
            for slot in request.get('slots', [])
        }

        try:
            yield from intent.async_handle(hass, DOMAIN, intent_type, slots,
                                           request['input'])
        except intent.IntentError:
            _LOGGER.exception("Error while handling intent.")
예제 #11
0
def async_handle_message(hass, message):
    """Handle a DialogFlow message."""
    req = message.get('result')
    action_incomplete = req['actionIncomplete']

    if action_incomplete:
        return None

    action = req.get('action', '')
    parameters = req.get('parameters')
    dialogflow_response = DialogflowResponse(parameters)

    if action == "":
        raise DialogFlowError(
            "You have not defined an action in your Dialogflow intent.")

    intent_response = yield from intent.async_handle(
        hass, DOMAIN, action,
        {key: {'value': value} for key, value
         in parameters.items()})

    if 'plain' in intent_response.speech:
        dialogflow_response.add_speech(
            intent_response.speech['plain']['speech'])

    return dialogflow_response.as_dict()
예제 #12
0
def test_add_item(hass, sl_setup):
    """Test adding an item intent."""

    response = yield from intent.async_handle(
        hass, "test", "HassShoppingListAddItem", {"item": {"value": "beer"}}
    )

    assert response.speech["plain"]["speech"] == "I've added beer to your shopping list"
예제 #13
0
    def post(self, request):
        """Handle Dialogflow."""
        hass = request.app['hass']
        data = yield from request.json()

        _LOGGER.debug("Received Dialogflow request: %s", data)

        req = data.get('result')

        if req is None:
            _LOGGER.error("Received invalid data from Dialogflow: %s", data)
            return self.json_message("Expected result value not received",
                                     HTTP_BAD_REQUEST)

        action_incomplete = req['actionIncomplete']

        if action_incomplete:
            return None

        action = req.get('action')
        parameters = req.get('parameters')
        dialogflow_response = DialogflowResponse(parameters)

        if action == "":
            _LOGGER.warning("Received intent with empty action")
            dialogflow_response.add_speech(
                "You have not defined an action in your Dialogflow intent.")
            return self.json(dialogflow_response)

        try:
            intent_response = yield from intent.async_handle(
                hass, DOMAIN, action,
                {key: {
                    'value': value
                }
                 for key, value in parameters.items()})

        except intent.UnknownIntent as err:
            _LOGGER.warning("Received unknown intent %s", action)
            dialogflow_response.add_speech(
                "This intent is not yet configured within Home Assistant.")
            return self.json(dialogflow_response)

        except intent.InvalidSlotInfo as err:
            _LOGGER.error("Received invalid slot data: %s", err)
            return self.json_message('Invalid slot data received',
                                     HTTP_BAD_REQUEST)
        except intent.IntentError:
            _LOGGER.exception("Error handling request for %s", action)
            return self.json_message('Error handling intent', HTTP_BAD_REQUEST)

        if 'plain' in intent_response.speech:
            dialogflow_response.add_speech(
                intent_response.speech['plain']['speech'])

        return self.json(dialogflow_response)
예제 #14
0
def test_add_item(hass):
    """Test adding an item intent."""
    yield from async_setup_component(hass, 'shopping_list', {})

    response = yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )

    assert response.speech['plain']['speech'] == \
        "I've added beer to your shopping list"
def test_add_item(hass):
    """Test adding an item intent."""
    yield from async_setup_component(hass, 'shopping_list', {})

    response = yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )

    assert response.speech['plain']['speech'] == \
        "I've added beer to your shopping list"
예제 #16
0
def test_recent_items_intent(hass, sl_setup):
    """Test recent items."""

    yield from intent.async_handle(
        hass, "test", "HassShoppingListAddItem", {"item": {"value": "beer"}}
    )
    yield from intent.async_handle(
        hass, "test", "HassShoppingListAddItem", {"item": {"value": "wine"}}
    )
    yield from intent.async_handle(
        hass, "test", "HassShoppingListAddItem", {"item": {"value": "soda"}}
    )

    response = yield from intent.async_handle(hass, "test", "HassShoppingListLastItems")

    assert (
        response.speech["plain"]["speech"]
        == "These are the top 3 items on your shopping list: soda, wine, beer"
    )
예제 #17
0
    def post(self, request):
        """Handle API.AI."""
        hass = request.app['hass']
        data = yield from request.json()

        _LOGGER.debug("Received api.ai request: %s", data)

        req = data.get('result')

        if req is None:
            _LOGGER.error("Received invalid data from api.ai: %s", data)
            return self.json_message(
                "Expected result value not received", HTTP_BAD_REQUEST)

        action_incomplete = req['actionIncomplete']

        if action_incomplete:
            return None

        action = req.get('action')
        parameters = req.get('parameters')
        apiai_response = ApiaiResponse(parameters)

        if action == "":
            _LOGGER.warning("Received intent with empty action")
            apiai_response.add_speech(
                "You have not defined an action in your api.ai intent.")
            return self.json(apiai_response)

        try:
            intent_response = yield from intent.async_handle(
                hass, DOMAIN, action,
                {key: {'value': value} for key, value
                 in parameters.items()})

        except intent.UnknownIntent as err:
            _LOGGER.warning('Received unknown intent %s', action)
            apiai_response.add_speech(
                "This intent is not yet configured within Home Assistant.")
            return self.json(apiai_response)

        except intent.InvalidSlotInfo as err:
            _LOGGER.error('Received invalid slot data: %s', err)
            return self.json_message('Invalid slot data received',
                                     HTTP_BAD_REQUEST)
        except intent.IntentError:
            _LOGGER.exception('Error handling request for %s', action)
            return self.json_message('Error handling intent', HTTP_BAD_REQUEST)

        if 'plain' in intent_response.speech:
            apiai_response.add_speech(
                intent_response.speech['plain']['speech'])

        return self.json(apiai_response)
def test_recent_items_intent(hass):
    """Test recent items."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'soda'}}
    )

    response = yield from intent.async_handle(
        hass, 'test', 'HassShoppingListLastItems'
    )

    assert response.speech['plain']['speech'] == \
        "These are the top 3 items on your shopping list: soda, wine, beer"
예제 #19
0
def test_deprecated_api_get_all(hass, hass_client, sl_setup):
    """Test the API."""

    yield from intent.async_handle(
        hass, "test", "HassShoppingListAddItem", {"item": {"value": "beer"}}
    )
    yield from intent.async_handle(
        hass, "test", "HassShoppingListAddItem", {"item": {"value": "wine"}}
    )

    client = yield from hass_client()
    resp = yield from client.get("/api/shopping_list")

    assert resp.status == 200
    data = yield from resp.json()
    assert len(data) == 2
    assert data[0]["name"] == "beer"
    assert not data[0]["complete"]
    assert data[1]["name"] == "wine"
    assert not data[1]["complete"]
예제 #20
0
def test_recent_items_intent(hass):
    """Test recent items."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'soda'}}
    )

    response = yield from intent.async_handle(
        hass, 'test', 'HassShoppingListLastItems'
    )

    assert response.speech['plain']['speech'] == \
        "These are the top 3 items on your shopping list: soda, wine, beer"
예제 #21
0
def test_api_get_all(hass, test_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )

    client = yield from test_client(hass.http.app)
    resp = yield from client.get('/api/shopping_list')

    assert resp.status == 200
    data = yield from resp.json()
    assert len(data) == 2
    assert data[0]['name'] == 'beer'
    assert not data[0]['complete']
    assert data[1]['name'] == 'wine'
    assert not data[1]['complete']
def _process(hass, text):
    """Process a line of text."""
    intents = hass.data.get(DOMAIN, {})

    for intent_type, matchers in intents.items():
        for matcher in matchers:
            match = matcher.match(text)

            if not match:
                continue

            response = yield from intent.async_handle(
                hass, DOMAIN, intent_type,
                {key: {'value': value} for key, value
                 in match.groupdict().items()}, text)
            return response

    from fuzzywuzzy import process as fuzzyExtract
    text = text.lower()
    match = REGEX_TURN_COMMAND.match(text)

    if not match:
        _LOGGER.error("Unable to process: %s", text)
        return None

    name, command = match.groups()
    entities = {state.entity_id: state.name for state
                in hass.states.async_all()}
    entity_ids = fuzzyExtract.extractOne(
        name, entities, score_cutoff=65)[2]

    if not entity_ids:
        _LOGGER.error(
            "Could not find entity id %s from text %s", name, text)
        return None

    if command == 'on':
        yield from hass.services.async_call(
            core.DOMAIN, SERVICE_TURN_ON, {
                ATTR_ENTITY_ID: entity_ids,
            }, blocking=True)

    elif command == 'off':
        yield from hass.services.async_call(
            core.DOMAIN, SERVICE_TURN_OFF, {
                ATTR_ENTITY_ID: entity_ids,
            }, blocking=True)

    else:
        _LOGGER.error('Got unsupported command %s from text %s',
                      command, text)

    return None
def test_api_get_all(hass, test_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )
    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}}
    )

    client = yield from test_client(hass.http.app)
    resp = yield from client.get('/api/shopping_list')

    assert resp.status == 200
    data = yield from resp.json()
    assert len(data) == 2
    assert data[0]['name'] == 'beer'
    assert not data[0]['complete']
    assert data[1]['name'] == 'wine'
    assert not data[1]['complete']
예제 #24
0
    def message_received(topic, payload, qos):
        """Handle new messages on MQTT."""
        _LOGGER.debug("New intent: %s", payload)

        try:
            request = json.loads(payload)
        except TypeError:
            _LOGGER.error('Received invalid JSON: %s', payload)
            return

        try:
            request = INTENT_SCHEMA(request)
        except vol.Invalid as err:
            _LOGGER.error('Intent has invalid schema: %s. %s', err, request)
            return

        snips_response = None

        if request['intent']['intentName'].startswith('user_'):
            intent_type = request['intent']['intentName'].split('__')[-1]
        else:
            intent_type = request['intent']['intentName'].split(':')[-1]
        slots = {}
        for slot in request.get('slots', []):
            slots[slot['slotName']] = {'value': resolve_slot_values(slot)}

        try:
            intent_response = yield from intent.async_handle(
                hass, DOMAIN, intent_type, slots, request['input'])
            if 'plain' in intent_response.speech:
                snips_response = intent_response.speech['plain']['speech']
        except intent.UnknownIntent as err:
            _LOGGER.warning("Received unknown intent %s",
                            request['intent']['intentName'])
            #snips_response = "Unknown Intent"
        except intent.IntentError:
            _LOGGER.exception("Error while handling intent: %s.", intent_type)
            snips_response = "Error while handling intent"

        notification = {
            'sessionId': request.get('sessionId', 'default'),
            'text': snips_response
        }

        _LOGGER.debug("send_response %s", json.dumps(notification))
        mqtt.async_publish(hass, 'hermes/dialogueManager/endSession',
                           json.dumps(notification))
예제 #25
0
def test_api_update_fails(hass, hass_client, sl_setup):
    """Test the API."""

    yield from intent.async_handle(hass, "test", "HassShoppingListAddItem",
                                   {"item": {
                                       "value": "beer"
                                   }})

    client = yield from hass_client()
    resp = yield from client.post("/api/shopping_list/non_existing",
                                  json={"name": "soda"})

    assert resp.status == 404

    beer_id = hass.data["shopping_list"].items[0]["id"]
    resp = yield from client.post("/api/shopping_list/item/{}".format(beer_id),
                                  json={"name": 123})

    assert resp.status == 400
예제 #26
0
def test_toggle_intent(hass):
    """Test HassToggle intent."""
    result = yield from comps.async_setup(hass, {})
    assert result

    hass.states.async_set('light.test_light', 'off')
    calls = async_mock_service(hass, 'light', SERVICE_TOGGLE)

    response = yield from intent.async_handle(
        hass, 'test', 'HassToggle', {'name': {'value': 'test light'}}
    )
    yield from hass.async_block_till_done()

    assert response.speech['plain']['speech'] == 'Toggled test light'
    assert len(calls) == 1
    call = calls[0]
    assert call.domain == 'light'
    assert call.service == 'toggle'
    assert call.data == {'entity_id': ['light.test_light']}
예제 #27
0
def async_handle_intent(hass, message):
    """Handle an intent request.

    Raises:
     - intent.UnknownIntent
     - intent.InvalidSlotInfo
     - intent.IntentError

    """
    req = message.get('request')
    alexa_intent_info = req.get('intent')
    alexa_response = AlexaResponse(hass, alexa_intent_info)

    if req['type'] == 'LaunchRequest':
        intent_name = message.get('session', {})  \
                             .get('application', {})  \
                             .get('applicationId')
    else:
        intent_name = alexa_intent_info['name']

    intent_response = yield from intent.async_handle(
        hass, DOMAIN, intent_name, {
            key: {
                'value': value
            }
            for key, value in alexa_response.variables.items()
        })

    for intent_speech, alexa_speech in SPEECH_MAPPINGS.items():
        if intent_speech in intent_response.speech:
            alexa_response.add_speech(
                alexa_speech, intent_response.speech[intent_speech]['speech'])
            break

    if 'simple' in intent_response.card:
        alexa_response.add_card(CardType.simple,
                                intent_response.card['simple']['title'],
                                intent_response.card['simple']['content'])

    return alexa_response.as_dict()
예제 #28
0
def test_intent_script(hass):
    """Test intent scripts work."""
    calls = async_mock_service(hass, "test", "service")

    yield from async_setup_component(
        hass,
        "intent_script",
        {
            "intent_script": {
                "HelloWorld": {
                    "action": {
                        "service": "test.service",
                        "data_template": {
                            "hello": "{{ name }}"
                        },
                    },
                    "card": {
                        "title": "Hello {{ name }}",
                        "content": "Content for {{ name }}",
                    },
                    "speech": {
                        "text": "Good morning {{ name }}"
                    },
                }
            }
        },
    )

    response = yield from intent.async_handle(hass, "test", "HelloWorld",
                                              {"name": {
                                                  "value": "Paulus"
                                              }})

    assert len(calls) == 1
    assert calls[0].data["hello"] == "Paulus"

    assert response.speech["plain"]["speech"] == "Good morning Paulus"

    assert response.card["simple"]["title"] == "Hello Paulus"
    assert response.card["simple"]["content"] == "Content for Paulus"
예제 #29
0
def test_api_update_fails(hass, hass_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(hass, 'test', 'HassShoppingListAddItem',
                                   {'item': {
                                       'value': 'beer'
                                   }})

    client = yield from hass_client()
    resp = yield from client.post('/api/shopping_list/non_existing',
                                  json={'name': 'soda'})

    assert resp.status == 404

    beer_id = hass.data['shopping_list'].items[0]['id']
    resp = yield from client.post('/api/shopping_list/item/{}'.format(beer_id),
                                  json={
                                      'name': 123,
                                  })

    assert resp.status == 400
예제 #30
0
def async_handle_intent(hass, message):
    """Handle an intent request.

    Raises:
     - intent.UnknownIntent
     - intent.InvalidSlotInfo
     - intent.IntentError

    """
    req = message.get('request')
    alexa_intent_info = req.get('intent')
    alexa_response = AlexaResponse(hass, alexa_intent_info)

    if req['type'] == 'LaunchRequest':
        intent_name = message.get('session', {})  \
                             .get('application', {})  \
                             .get('applicationId')
    else:
        intent_name = alexa_intent_info['name']

    intent_response = yield from intent.async_handle(
        hass, DOMAIN, intent_name,
        {key: {'value': value} for key, value
         in alexa_response.variables.items()})

    for intent_speech, alexa_speech in SPEECH_MAPPINGS.items():
        if intent_speech in intent_response.speech:
            alexa_response.add_speech(
                alexa_speech,
                intent_response.speech[intent_speech]['speech'])
            break

    if 'simple' in intent_response.card:
        alexa_response.add_card(
            CardType.simple, intent_response.card['simple']['title'],
            intent_response.card['simple']['content'])

    return alexa_response.as_dict()
def test_api_update_fails(hass, test_client):
    """Test the API."""
    yield from async_setup_component(hass, 'shopping_list', {})

    yield from intent.async_handle(
        hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}}
    )

    client = yield from test_client(hass.http.app)
    resp = yield from client.post(
        '/api/shopping_list/non_existing', json={
            'name': 'soda'
        })

    assert resp.status == 404

    beer_id = hass.data['shopping_list'].items[0]['id']
    resp = yield from client.post(
        '/api/shopping_list/item/{}'.format(beer_id), json={
            'name': 123,
        })

    assert resp.status == 400
예제 #32
0
def test_turn_on_multiple_intent(hass):
    """Test HassTurnOn intent with multiple similar entities.

    This tests that matching finds the proper entity among similar names.
    """
    result = yield from comps.async_setup(hass, {})
    assert result

    hass.states.async_set('light.test_light', 'off')
    hass.states.async_set('light.test_lights_2', 'off')
    hass.states.async_set('light.test_lighter', 'off')
    calls = async_mock_service(hass, 'light', SERVICE_TURN_ON)

    response = yield from intent.async_handle(
        hass, 'test', 'HassTurnOn', {'name': {'value': 'test lights'}}
    )
    yield from hass.async_block_till_done()

    assert response.speech['plain']['speech'] == 'Turned test lights 2 on'
    assert len(calls) == 1
    call = calls[0]
    assert call.domain == 'light'
    assert call.service == 'turn_on'
    assert call.data == {'entity_id': ['light.test_lights_2']}
예제 #33
0
    def async_parse(call):
        message = call.data[ATTR_MESSAGE]
        project_name = call.data[ATTR_PROJECT_NAME]

        # idle -> thinking
        hass.states.async_set(OBJECT_RECOGNIZER, STATE_THINKING, state_attrs)

        # Run parsing in a separate thread
        result = {}
        parse_event = threading.Event()

        def parse():
            nonlocal result
            result = hass.data[DOMAIN].parse(message, project_name)
            parse_event.set()

        thread = threading.Thread(target=parse, daemon=True)
        thread.start()

        loop = asyncio.get_event_loop()
        yield from loop.run_in_executor(None, parse_event.wait)

        # Deconstruct result
        intent_type = ''
        if 'intent' in result:
            intent_type = result['intent']['name']
            slots = {}

            if 'entities' in result:
                # This will unfortunately only allow for one value per entity (slot).
                # rasaNLU supports multiple values per slot, but hass doesn't seem to.
                for entity_value in result['entities']:
                    slots[entity_value['entity']] = {
                        'value': entity_value['value']
                    }

            try:
                # Try to handle the intent with hass
                yield from intent.async_handle(hass,
                                               DOMAIN,
                                               intent_type,
                                               slots=slots,
                                               text_input=message)

                # Fire known intent event
                hass.bus.async_fire(
                    EVENT_KNOWN_INTENT,
                    {
                        'name': name,  # name of the component
                        'intent_type': intent_type,  # type of intent
                        'slots': slots,  # slots and values
                        'message': message  # text provided
                    })
            except:
                # Fire unknown intent event
                hass.bus.async_fire(
                    EVENT_UNKNOWN_INTENT,
                    {
                        'name': name,  # name of the component
                        'message': message  # text provided
                    })

        state_attrs['intent'] = intent_type

        # thinking -> idle
        hass.states.async_set(OBJECT_RECOGNIZER, STATE_IDLE, state_attrs)
예제 #34
0
    def post(self, request):
        """Handle Alexa."""
        hass = request.app['hass']
        data = yield from request.json()

        _LOGGER.debug('Received Alexa request: %s', data)

        req = data.get('request')

        if req is None:
            _LOGGER.error('Received invalid data from Alexa: %s', data)
            return self.json_message('Expected request value not received',
                                     HTTP_BAD_REQUEST)

        req_type = req['type']

        if req_type == 'SessionEndedRequest':
            return None

        alexa_intent_info = req.get('intent')
        alexa_response = AlexaResponse(hass, alexa_intent_info)

        if req_type != 'IntentRequest' and req_type != 'LaunchRequest':
            _LOGGER.warning('Received unsupported request: %s', req_type)
            return self.json_message(
                'Received unsupported request: {}'.format(req_type),
                HTTP_BAD_REQUEST)

        if req_type == 'LaunchRequest':
            intent_name = data.get('session', {})       \
                              .get('application', {})   \
                              .get('applicationId')
        else:
            intent_name = alexa_intent_info['name']

        try:
            intent_response = yield from intent.async_handle(
                hass, DOMAIN, intent_name,
                {key: {'value': value} for key, value
                 in alexa_response.variables.items()})
        except intent.UnknownIntent as err:
            _LOGGER.warning('Received unknown intent %s', intent_name)
            alexa_response.add_speech(
                SpeechType.plaintext,
                "This intent is not yet configured within Home Assistant.")
            return self.json(alexa_response)

        except intent.InvalidSlotInfo as err:
            _LOGGER.error('Received invalid slot data from Alexa: %s', err)
            return self.json_message('Invalid slot data received',
                                     HTTP_BAD_REQUEST)
        except intent.IntentError:
            _LOGGER.exception('Error handling request for %s', intent_name)
            return self.json_message('Error handling intent', HTTP_BAD_REQUEST)

        for intent_speech, alexa_speech in SPEECH_MAPPINGS.items():
            if intent_speech in intent_response.speech:
                alexa_response.add_speech(
                    alexa_speech,
                    intent_response.speech[intent_speech]['speech'])
                break

        if 'simple' in intent_response.card:
            alexa_response.add_card(
                CardType.simple, intent_response.card['simple']['title'],
                intent_response.card['simple']['content'])

        return self.json(alexa_response)