예제 #1
0
async def test_custom_agent(hass, hass_client):
    """Test a custom conversation agent."""
    class MyAgent(conversation.AbstractConversationAgent):
        """Test Agent."""
        async def async_process(self, text):
            """Process some text."""
            response = intent.IntentResponse()
            response.async_set_speech("Test response")
            return response

    conversation.async_set_agent(hass, MyAgent())

    assert await async_setup_component(hass, "conversation", {})

    client = await hass_client()

    resp = await client.post("/api/conversation/process",
                             json={"text": "Test Text"})
    assert resp.status == 200
    assert await resp.json() == {
        "card": {},
        "speech": {
            "plain": {
                "extra_data": None,
                "speech": "Test response"
            }
        },
    }
예제 #2
0
async def async_setup_entry(hass: HomeAssistant,
                            entry: config_entries.ConfigEntry):
    """Set up Almond config entry."""
    websession = aiohttp_client.async_get_clientsession(hass)

    if entry.data["type"] == TYPE_LOCAL:
        auth = AlmondLocalAuth(entry.data["host"], websession)
    else:
        # OAuth2
        implementation = (
            await
            config_entry_oauth2_flow.async_get_config_entry_implementation(
                hass, entry))
        oauth_session = config_entry_oauth2_flow.OAuth2Session(
            hass, entry, implementation)
        auth = AlmondOAuth(entry.data["host"], websession, oauth_session)

    api = WebAlmondAPI(auth)
    agent = AlmondAgent(hass, api, entry)

    # Hass.io does its own configuration.
    if not entry.data.get("is_hassio"):
        # If we're not starting or local, set up Almond right away
        if hass.state != CoreState.not_running or entry.data[
                "type"] == TYPE_LOCAL:
            await _configure_almond_for_ha(hass, entry, api)

        else:
            # OAuth2 implementations can potentially rely on the HA Cloud url.
            # This url is not be available until 30 seconds after boot.

            async def configure_almond(_now):
                try:
                    await _configure_almond_for_ha(hass, entry, api)
                except ConfigEntryNotReady:
                    _LOGGER.warning(
                        "Unable to configure Almond to connect to Home Assistant"
                    )

            async def almond_hass_start(_event):
                event.async_call_later(hass, ALMOND_SETUP_DELAY,
                                       configure_almond)

            hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START,
                                       almond_hass_start)

    conversation.async_set_agent(hass, agent)
    return True
예제 #3
0
async def test_custom_agent(hass, hass_client, hass_admin_user):
    """Test a custom conversation agent."""

    calls = []

    class MyAgent(conversation.AbstractConversationAgent):
        """Test Agent."""
        async def async_process(self, text, context, conversation_id):
            """Process some text."""
            calls.append((text, context, conversation_id))
            response = intent.IntentResponse()
            response.async_set_speech("Test response")
            return response

    conversation.async_set_agent(hass, MyAgent())

    assert await async_setup_component(hass, "conversation", {})

    client = await hass_client()

    resp = await client.post(
        "/api/conversation/process",
        json={
            "text": "Test Text",
            "conversation_id": "test-conv-id"
        },
    )
    assert resp.status == HTTPStatus.OK
    assert await resp.json() == {
        "card": {},
        "speech": {
            "plain": {
                "extra_data": None,
                "speech": "Test response"
            }
        },
    }

    assert len(calls) == 1
    assert calls[0][0] == "Test Text"
    assert calls[0][1].user_id == hass_admin_user.id
    assert calls[0][2] == "test-conv-id"
예제 #4
0
async def async_unload_entry(hass, entry):
    """Unload Almond."""
    conversation.async_set_agent(hass, None)
    return True
예제 #5
0
async def async_setup_entry(hass, entry):
    """Set up Almond config entry."""
    websession = aiohttp_client.async_get_clientsession(hass)

    if entry.data["type"] == TYPE_LOCAL:
        auth = AlmondLocalAuth(entry.data["host"], websession)
    else:
        # OAuth2
        implementation = await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry)
        oauth_session = config_entry_oauth2_flow.OAuth2Session(
            hass, entry, implementation)
        auth = AlmondOAuth(entry.data["host"], websession, oauth_session)

    api = WebAlmondAPI(auth)
    agent = AlmondAgent(hass, api, entry)

    # Hass.io does its own configuration of Almond.
    if entry.data.get("is_hassio") or entry.data["type"] != TYPE_LOCAL:
        conversation.async_set_agent(hass, agent)
        return True

    # Configure Almond to connect to Home Assistant
    store = storage.Store(hass, STORAGE_VERSION, STORAGE_KEY)
    data = await store.async_load()

    if data is None:
        data = {}

    user = None
    if "almond_user" in data:
        user = await hass.auth.async_get_user(data["almond_user"])

    if user is None:
        user = await hass.auth.async_create_system_user(
            "Almond", [GROUP_ID_ADMIN])
        data["almond_user"] = user.id
        await store.async_save(data)

    refresh_token = await hass.auth.async_create_refresh_token(
        user,
        # Almond will be fine as long as we restart once every 5 years
        access_token_expiration=timedelta(days=365 * 5),
    )

    # Create long lived access token
    access_token = hass.auth.async_create_access_token(refresh_token)

    # Store token in Almond
    try:
        with async_timeout.timeout(10):
            await api.async_create_device({
                "kind":
                "io.home-assistant",
                "hassUrl":
                hass.config.api.base_url,
                "accessToken":
                access_token,
                "refreshToken":
                "",
                # 5 years from now in ms.
                "accessTokenExpires":
                (time.time() + 60 * 60 * 24 * 365 * 5) * 1000,
            })
    except (asyncio.TimeoutError, ClientError) as err:
        if isinstance(err, asyncio.TimeoutError):
            msg = "Request timeout"
        else:
            msg = err
        _LOGGER.warning("Unable to configure Almond: %s", msg)
        await hass.auth.async_remove_refresh_token(refresh_token)
        raise ConfigEntryNotReady

    # Clear all other refresh tokens
    for token in list(user.refresh_tokens.values()):
        if token.id != refresh_token.id:
            await hass.auth.async_remove_refresh_token(token)

    conversation.async_set_agent(hass, agent)
    return True
예제 #6
0
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Unload Almond."""
    conversation.async_set_agent(hass, None)
    return True