Get room hints from areas (#21519)

* Get google room hint from area.

* Test case for area code.

* Updates as per code review.
This commit is contained in:
Penny Wood 2019-03-02 15:31:57 +08:00 committed by Paulus Schoutsen
parent 0c8a31b8ec
commit f61f650495
2 changed files with 121 additions and 9 deletions

View File

@ -1,4 +1,5 @@
"""Support for Google Assistant Smart Home API."""
from asyncio import gather
from collections.abc import Mapping
from itertools import product
import logging
@ -89,8 +90,7 @@ class _GoogleEntity:
return [Trait(self.hass, state, self.config) for Trait in trait.TRAITS
if Trait.supported(domain, features)]
@callback
def sync_serialize(self):
async def sync_serialize(self):
"""Serialize entity for a SYNC response.
https://developers.google.com/actions/smarthome/create-app#actiondevicessync
@ -132,13 +132,31 @@ class _GoogleEntity:
if aliases:
device['name']['nicknames'] = aliases
# add room hint if annotated
for trt in traits:
device['attributes'].update(trt.sync_attributes())
room = entity_config.get(CONF_ROOM_HINT)
if room:
device['roomHint'] = room
return device
for trt in traits:
device['attributes'].update(trt.sync_attributes())
dev_reg, ent_reg, area_reg = await gather(
self.hass.helpers.device_registry.async_get_registry(),
self.hass.helpers.entity_registry.async_get_registry(),
self.hass.helpers.area_registry.async_get_registry(),
)
entity_entry = ent_reg.async_get(state.entity_id)
if not (entity_entry and entity_entry.device_id):
return device
device_entry = dev_reg.devices.get(entity_entry.device_id)
if not (device_entry and device_entry.area_id):
return device
area_entry = area_reg.areas.get(device_entry.area_id)
if area_entry and area_entry.name:
device['roomHint'] = area_entry.name
return device
@ -253,7 +271,7 @@ async def async_devices_sync(hass, config, request_id, payload):
continue
entity = _GoogleEntity(hass, config, state)
serialized = entity.sync_serialize()
serialized = await entity.sync_serialize()
if serialized is None:
_LOGGER.debug("No mapping for %s domain", entity.state)

View File

@ -1,4 +1,6 @@
"""Test Google Smart Home."""
import pytest
from homeassistant.core import State
from homeassistant.const import (
ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS)
@ -11,6 +13,9 @@ from homeassistant.components.google_assistant import (
EVENT_COMMAND_RECEIVED, EVENT_QUERY_RECEIVED, EVENT_SYNC_RECEIVED)
from homeassistant.components.light.demo import DemoLight
from homeassistant.helpers import device_registry
from tests.common import (mock_device_registry, mock_registry,
mock_area_registry)
BASIC_CONFIG = helpers.Config(
should_expose=lambda state: True,
@ -20,6 +25,17 @@ BASIC_CONFIG = helpers.Config(
REQ_ID = 'ff36a3cc-ec34-11e6-b1a0-64510650abcf'
@pytest.fixture
def registries(hass):
"""Registry mock setup."""
from types import SimpleNamespace
ret = SimpleNamespace()
ret.entity = mock_registry(hass)
ret.device = mock_device_registry(hass)
ret.area = mock_area_registry(hass)
return ret
async def test_sync_message(hass):
"""Test a sync message."""
light = DemoLight(
@ -98,6 +114,83 @@ async def test_sync_message(hass):
}
async def test_sync_in_area(hass, registries):
"""Test a sync message where room hint comes from area."""
area = registries.area.async_create("Living Room")
device = registries.device.async_get_or_create(
config_entry_id='1234',
connections={
(device_registry.CONNECTION_NETWORK_MAC, '12:34:56:AB:CD:EF')
})
registries.device.async_update_device(device.id, area_id=area.id)
entity = registries.entity.async_get_or_create(
'light', 'test', '1235',
suggested_object_id='demo_light',
device_id=device.id)
light = DemoLight(
None, 'Demo Light',
state=False,
hs_color=(180, 75),
)
light.hass = hass
light.entity_id = entity.entity_id
await light.async_update_ha_state()
config = helpers.Config(
should_expose=lambda _: True,
allow_unlock=False,
agent_user_id='test-agent',
entity_config={}
)
events = []
hass.bus.async_listen(EVENT_SYNC_RECEIVED, events.append)
result = await sh.async_handle_message(hass, config, {
"requestId": REQ_ID,
"inputs": [{
"intent": "action.devices.SYNC"
}]
})
assert result == {
'requestId': REQ_ID,
'payload': {
'agentUserId': 'test-agent',
'devices': [{
'id': 'light.demo_light',
'name': {
'name': 'Demo Light'
},
'traits': [
trait.TRAIT_BRIGHTNESS,
trait.TRAIT_ONOFF,
trait.TRAIT_COLOR_SPECTRUM,
trait.TRAIT_COLOR_TEMP,
],
'type': sh.TYPE_LIGHT,
'willReportState': False,
'attributes': {
'colorModel': 'rgb',
'temperatureMinK': 2000,
'temperatureMaxK': 6535,
},
'roomHint': 'Living Room'
}]
}
}
await hass.async_block_till_done()
assert len(events) == 1
assert events[0].event_type == EVENT_SYNC_RECEIVED
assert events[0].data == {
'request_id': REQ_ID,
}
async def test_query_message(hass):
"""Test a sync message."""
light = DemoLight(
@ -350,11 +443,12 @@ async def test_raising_error_trait(hass):
}
def test_serialize_input_boolean():
async def test_serialize_input_boolean(hass):
"""Test serializing an input boolean entity."""
state = State('input_boolean.bla', 'on')
entity = sh._GoogleEntity(None, BASIC_CONFIG, state)
assert entity.sync_serialize() == {
entity = sh._GoogleEntity(hass, BASIC_CONFIG, state)
result = await entity.sync_serialize()
assert result == {
'id': 'input_boolean.bla',
'attributes': {},
'name': {'name': 'bla'},