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.""" """Support for Google Assistant Smart Home API."""
from asyncio import gather
from collections.abc import Mapping from collections.abc import Mapping
from itertools import product from itertools import product
import logging import logging
@ -89,8 +90,7 @@ class _GoogleEntity:
return [Trait(self.hass, state, self.config) for Trait in trait.TRAITS return [Trait(self.hass, state, self.config) for Trait in trait.TRAITS
if Trait.supported(domain, features)] if Trait.supported(domain, features)]
@callback async def sync_serialize(self):
def sync_serialize(self):
"""Serialize entity for a SYNC response. """Serialize entity for a SYNC response.
https://developers.google.com/actions/smarthome/create-app#actiondevicessync https://developers.google.com/actions/smarthome/create-app#actiondevicessync
@ -132,13 +132,31 @@ class _GoogleEntity:
if aliases: if aliases:
device['name']['nicknames'] = 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) room = entity_config.get(CONF_ROOM_HINT)
if room: if room:
device['roomHint'] = room device['roomHint'] = room
return device
for trt in traits: dev_reg, ent_reg, area_reg = await gather(
device['attributes'].update(trt.sync_attributes()) 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 return device
@ -253,7 +271,7 @@ async def async_devices_sync(hass, config, request_id, payload):
continue continue
entity = _GoogleEntity(hass, config, state) entity = _GoogleEntity(hass, config, state)
serialized = entity.sync_serialize() serialized = await entity.sync_serialize()
if serialized is None: if serialized is None:
_LOGGER.debug("No mapping for %s domain", entity.state) _LOGGER.debug("No mapping for %s domain", entity.state)

View File

@ -1,4 +1,6 @@
"""Test Google Smart Home.""" """Test Google Smart Home."""
import pytest
from homeassistant.core import State from homeassistant.core import State
from homeassistant.const import ( from homeassistant.const import (
ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS) 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) EVENT_COMMAND_RECEIVED, EVENT_QUERY_RECEIVED, EVENT_SYNC_RECEIVED)
from homeassistant.components.light.demo import DemoLight 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( BASIC_CONFIG = helpers.Config(
should_expose=lambda state: True, should_expose=lambda state: True,
@ -20,6 +25,17 @@ BASIC_CONFIG = helpers.Config(
REQ_ID = 'ff36a3cc-ec34-11e6-b1a0-64510650abcf' 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): async def test_sync_message(hass):
"""Test a sync message.""" """Test a sync message."""
light = DemoLight( 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): async def test_query_message(hass):
"""Test a sync message.""" """Test a sync message."""
light = DemoLight( 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.""" """Test serializing an input boolean entity."""
state = State('input_boolean.bla', 'on') state = State('input_boolean.bla', 'on')
entity = sh._GoogleEntity(None, BASIC_CONFIG, state) entity = sh._GoogleEntity(hass, BASIC_CONFIG, state)
assert entity.sync_serialize() == { result = await entity.sync_serialize()
assert result == {
'id': 'input_boolean.bla', 'id': 'input_boolean.bla',
'attributes': {}, 'attributes': {},
'name': {'name': 'bla'}, 'name': {'name': 'bla'},