home-assistant/tests/components/google_assistant/test_google_assistant.py
Rami Mosleh d1adb28c6b Add google_assistant alarm_control_panel (#26249)
* add alarm_control_panel to google_assistant

* add cancel arming option

* raise error if requested state is same as current

* rework executing command logic

* Add tests

* fixed tests

* fixed level synonyms
2019-09-25 10:13:31 -07:00

395 lines
13 KiB
Python

"""The tests for the Google Assistant component."""
# pylint: disable=protected-access
import asyncio
import json
from aiohttp.hdrs import CONTENT_TYPE, AUTHORIZATION
import pytest
from homeassistant import core, const, setup
from homeassistant.components import (
fan,
cover,
light,
switch,
lock,
media_player,
alarm_control_panel,
)
from homeassistant.components.climate import const as climate
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.components import google_assistant as ga
from . import DEMO_DEVICES
API_PASSWORD = "test1234"
HA_HEADERS = {
const.HTTP_HEADER_HA_AUTH: API_PASSWORD,
CONTENT_TYPE: const.CONTENT_TYPE_JSON,
}
PROJECT_ID = "hasstest-1234"
CLIENT_ID = "helloworld"
ACCESS_TOKEN = "superdoublesecret"
@pytest.fixture
def auth_header(hass_access_token):
"""Generate an HTTP header with bearer token authorization."""
return {AUTHORIZATION: "Bearer {}".format(hass_access_token)}
@pytest.fixture
def assistant_client(loop, hass, aiohttp_client):
"""Create web client for the Google Assistant API."""
loop.run_until_complete(
setup.async_setup_component(
hass,
"google_assistant",
{
"google_assistant": {
"project_id": PROJECT_ID,
"entity_config": {
"light.ceiling_lights": {
"aliases": ["top lights", "ceiling lights"],
"name": "Roof Lights",
}
},
}
},
)
)
return loop.run_until_complete(aiohttp_client(hass.http.app))
@pytest.fixture
def hass_fixture(loop, hass):
"""Set up a Home Assistant instance for these tests."""
# We need to do this to get access to homeassistant/turn_(on,off)
loop.run_until_complete(setup.async_setup_component(hass, core.DOMAIN, {}))
loop.run_until_complete(
setup.async_setup_component(
hass, light.DOMAIN, {"light": [{"platform": "demo"}]}
)
)
loop.run_until_complete(
setup.async_setup_component(
hass, switch.DOMAIN, {"switch": [{"platform": "demo"}]}
)
)
loop.run_until_complete(
setup.async_setup_component(
hass, cover.DOMAIN, {"cover": [{"platform": "demo"}]}
)
)
loop.run_until_complete(
setup.async_setup_component(
hass, media_player.DOMAIN, {"media_player": [{"platform": "demo"}]}
)
)
loop.run_until_complete(
setup.async_setup_component(hass, fan.DOMAIN, {"fan": [{"platform": "demo"}]})
)
loop.run_until_complete(
setup.async_setup_component(
hass, climate.DOMAIN, {"climate": [{"platform": "demo"}]}
)
)
loop.run_until_complete(
setup.async_setup_component(hass, lock.DOMAIN, {"lock": [{"platform": "demo"}]})
)
loop.run_until_complete(
setup.async_setup_component(
hass,
alarm_control_panel.DOMAIN,
{"alarm_control_panel": [{"platform": "demo"}]},
)
)
return hass
# pylint: disable=redefined-outer-name
@asyncio.coroutine
def test_sync_request(hass_fixture, assistant_client, auth_header):
"""Test a sync request."""
reqid = "5711642932632160983"
data = {"requestId": reqid, "inputs": [{"intent": "action.devices.SYNC"}]}
result = yield from assistant_client.post(
ga.const.GOOGLE_ASSISTANT_API_ENDPOINT,
data=json.dumps(data),
headers=auth_header,
)
assert result.status == 200
body = yield from result.json()
assert body.get("requestId") == reqid
devices = body["payload"]["devices"]
assert sorted([dev["id"] for dev in devices]) == sorted(
[dev["id"] for dev in DEMO_DEVICES]
)
for dev in devices:
assert dev["id"] not in CLOUD_NEVER_EXPOSED_ENTITIES
for dev, demo in zip(
sorted(devices, key=lambda d: d["id"]),
sorted(DEMO_DEVICES, key=lambda d: d["id"]),
):
assert dev["name"] == demo["name"]
assert set(dev["traits"]) == set(demo["traits"])
assert dev["type"] == demo["type"]
@asyncio.coroutine
def test_query_request(hass_fixture, assistant_client, auth_header):
"""Test a query request."""
reqid = "5711642932632160984"
data = {
"requestId": reqid,
"inputs": [
{
"intent": "action.devices.QUERY",
"payload": {
"devices": [
{"id": "light.ceiling_lights"},
{"id": "light.bed_light"},
{"id": "light.kitchen_lights"},
{"id": "media_player.lounge_room"},
]
},
}
],
}
result = yield from assistant_client.post(
ga.const.GOOGLE_ASSISTANT_API_ENDPOINT,
data=json.dumps(data),
headers=auth_header,
)
assert result.status == 200
body = yield from result.json()
assert body.get("requestId") == reqid
devices = body["payload"]["devices"]
assert len(devices) == 4
assert devices["light.bed_light"]["on"] is False
assert devices["light.ceiling_lights"]["on"] is True
assert devices["light.ceiling_lights"]["brightness"] == 70
assert devices["light.kitchen_lights"]["color"]["spectrumHsv"] == {
"hue": 345,
"saturation": 0.75,
"value": 0.7058823529411765,
}
assert devices["light.kitchen_lights"]["color"]["temperatureK"] == 4166
assert devices["media_player.lounge_room"]["on"] is True
@asyncio.coroutine
def test_query_climate_request(hass_fixture, assistant_client, auth_header):
"""Test a query request."""
reqid = "5711642932632160984"
data = {
"requestId": reqid,
"inputs": [
{
"intent": "action.devices.QUERY",
"payload": {
"devices": [
{"id": "climate.hvac"},
{"id": "climate.heatpump"},
{"id": "climate.ecobee"},
]
},
}
],
}
result = yield from assistant_client.post(
ga.const.GOOGLE_ASSISTANT_API_ENDPOINT,
data=json.dumps(data),
headers=auth_header,
)
assert result.status == 200
body = yield from result.json()
assert body.get("requestId") == reqid
devices = body["payload"]["devices"]
assert len(devices) == 3
assert devices["climate.heatpump"] == {
"online": True,
"thermostatTemperatureSetpoint": 20.0,
"thermostatTemperatureAmbient": 25.0,
"thermostatMode": "heat",
}
assert devices["climate.ecobee"] == {
"online": True,
"thermostatTemperatureSetpointHigh": 24,
"thermostatTemperatureAmbient": 23,
"thermostatMode": "heatcool",
"thermostatTemperatureSetpointLow": 21,
}
assert devices["climate.hvac"] == {
"online": True,
"thermostatTemperatureSetpoint": 21,
"thermostatTemperatureAmbient": 22,
"thermostatMode": "cool",
"thermostatHumidityAmbient": 54,
}
@asyncio.coroutine
def test_query_climate_request_f(hass_fixture, assistant_client, auth_header):
"""Test a query request."""
# Mock demo devices as fahrenheit to see if we convert to celsius
hass_fixture.config.units.temperature_unit = const.TEMP_FAHRENHEIT
for entity_id in ("climate.hvac", "climate.heatpump", "climate.ecobee"):
state = hass_fixture.states.get(entity_id)
attr = dict(state.attributes)
hass_fixture.states.async_set(entity_id, state.state, attr)
reqid = "5711642932632160984"
data = {
"requestId": reqid,
"inputs": [
{
"intent": "action.devices.QUERY",
"payload": {
"devices": [
{"id": "climate.hvac"},
{"id": "climate.heatpump"},
{"id": "climate.ecobee"},
]
},
}
],
}
result = yield from assistant_client.post(
ga.const.GOOGLE_ASSISTANT_API_ENDPOINT,
data=json.dumps(data),
headers=auth_header,
)
assert result.status == 200
body = yield from result.json()
assert body.get("requestId") == reqid
devices = body["payload"]["devices"]
assert len(devices) == 3
assert devices["climate.heatpump"] == {
"online": True,
"thermostatTemperatureSetpoint": -6.7,
"thermostatTemperatureAmbient": -3.9,
"thermostatMode": "heat",
}
assert devices["climate.ecobee"] == {
"online": True,
"thermostatTemperatureSetpointHigh": -4.4,
"thermostatTemperatureAmbient": -5,
"thermostatMode": "heatcool",
"thermostatTemperatureSetpointLow": -6.1,
}
assert devices["climate.hvac"] == {
"online": True,
"thermostatTemperatureSetpoint": -6.1,
"thermostatTemperatureAmbient": -5.6,
"thermostatMode": "cool",
"thermostatHumidityAmbient": 54,
}
hass_fixture.config.units.temperature_unit = const.TEMP_CELSIUS
@asyncio.coroutine
def test_execute_request(hass_fixture, assistant_client, auth_header):
"""Test an execute request."""
reqid = "5711642932632160985"
data = {
"requestId": reqid,
"inputs": [
{
"intent": "action.devices.EXECUTE",
"payload": {
"commands": [
{
"devices": [
{"id": "light.ceiling_lights"},
{"id": "switch.decorative_lights"},
{"id": "media_player.lounge_room"},
],
"execution": [
{
"command": "action.devices.commands.OnOff",
"params": {"on": False},
}
],
},
{
"devices": [{"id": "media_player.walkman"}],
"execution": [
{
"command": "action.devices.commands.setVolume",
"params": {"volumeLevel": 70},
}
],
},
{
"devices": [{"id": "light.kitchen_lights"}],
"execution": [
{
"command": "action.devices.commands.ColorAbsolute",
"params": {"color": {"spectrumRGB": 16711680}},
}
],
},
{
"devices": [{"id": "light.bed_light"}],
"execution": [
{
"command": "action.devices.commands.ColorAbsolute",
"params": {"color": {"spectrumRGB": 65280}},
},
{
"command": "action.devices.commands.ColorAbsolute",
"params": {"color": {"temperature": 4700}},
},
],
},
]
},
}
],
}
result = yield from assistant_client.post(
ga.const.GOOGLE_ASSISTANT_API_ENDPOINT,
data=json.dumps(data),
headers=auth_header,
)
assert result.status == 200
body = yield from result.json()
assert body.get("requestId") == reqid
commands = body["payload"]["commands"]
assert len(commands) == 6
assert not any(result["status"] == "ERROR" for result in commands)
ceiling = hass_fixture.states.get("light.ceiling_lights")
assert ceiling.state == "off"
kitchen = hass_fixture.states.get("light.kitchen_lights")
assert kitchen.attributes.get(light.ATTR_RGB_COLOR) == (255, 0, 0)
bed = hass_fixture.states.get("light.bed_light")
assert bed.attributes.get(light.ATTR_COLOR_TEMP) == 212
assert bed.attributes.get(light.ATTR_RGB_COLOR) == (0, 255, 0)
assert hass_fixture.states.get("switch.decorative_lights").state == "off"
walkman = hass_fixture.states.get("media_player.walkman")
assert walkman.state == "playing"
assert walkman.attributes.get(media_player.ATTR_MEDIA_VOLUME_LEVEL) == 0.7
lounge = hass_fixture.states.get("media_player.lounge_room")
assert lounge.state == "off"