Report states (#11973)

* Refactor Alexa Smart Home API

Having an object per interface will make it easier to support
properties.

Ideally, properties are reported in context in all responses. However
current implementation reports them only in response to a ReportState
request. This seems to work sufficiently. As long as the device is
opened in the Alexa app, Amazon will poll the device state every few
seconds with a ReportState request.

* Report properties for some Alexa interfaces

Fixes (mostly) #11874.

Other interfaces will need properties implemented as well.

Implementing properties for just PowerController seems sufficient to
eliminate the "There was a problem." error for any device that supports
it, even if other interfaces are supported. Of course the additional
properties will be reported incorrectly in the Alexa app.

Includes a minor bugfix: `reportable` was previously placed incorrectly
in the responses, so Amazon was ignoring it.
This commit is contained in:
Phil Frost 2018-01-29 01:00:34 +00:00 committed by Paulus Schoutsen
parent 84711aad90
commit 7d6ef4445e
2 changed files with 142 additions and 6 deletions

View file

@ -5,9 +5,11 @@ from uuid import uuid4
import pytest
from homeassistant.const import TEMP_FAHRENHEIT, CONF_UNIT_OF_MEASUREMENT
from homeassistant.const import (
TEMP_FAHRENHEIT, CONF_UNIT_OF_MEASUREMENT, STATE_LOCKED, STATE_UNLOCKED,
STATE_UNKNOWN, STATE_ON, STATE_OFF)
from homeassistant.setup import async_setup_component
from homeassistant.components import alexa
from homeassistant.components import alexa, light
from homeassistant.components.alexa import smart_home
from homeassistant.helpers import entityfilter
@ -379,8 +381,8 @@ def test_discovery_request(hass):
assert len(appliance['capabilities']) == 1
capability = appliance['capabilities'][0]
assert capability['interface'] == 'Alexa.TemperatureSensor'
assert capability['retrievable'] is True
properties = capability['properties']
assert properties['retrievable'] is True
assert {'name': 'temperature'} in properties['supported']
continue
@ -1248,6 +1250,99 @@ def test_api_report_temperature(hass):
assert prop['value'] == {'value': 42.0, 'scale': 'FAHRENHEIT'}
@asyncio.coroutine
def test_report_lock_state(hass):
"""Test LockController implements lockState property."""
hass.states.async_set(
'lock.locked', STATE_LOCKED, {})
hass.states.async_set(
'lock.unlocked', STATE_UNLOCKED, {})
hass.states.async_set(
'lock.unknown', STATE_UNKNOWN, {})
request = get_new_request('Alexa', 'ReportState', 'lock#locked')
msg = yield from smart_home.async_handle_message(
hass, DEFAULT_CONFIG, request)
yield from hass.async_block_till_done()
properties = msg['context']['properties']
assert len(properties) == 1
prop = properties[0]
assert prop['namespace'] == 'Alexa.LockController'
assert prop['name'] == 'lockState'
assert prop['value'] == 'LOCKED'
request = get_new_request('Alexa', 'ReportState', 'lock#unlocked')
msg = yield from smart_home.async_handle_message(
hass, DEFAULT_CONFIG, request)
yield from hass.async_block_till_done()
properties = msg['context']['properties']
prop = properties[0]
assert prop['value'] == 'UNLOCKED'
request = get_new_request('Alexa', 'ReportState', 'lock#unknown')
msg = yield from smart_home.async_handle_message(
hass, DEFAULT_CONFIG, request)
yield from hass.async_block_till_done()
properties = msg['context']['properties']
prop = properties[0]
assert prop['value'] == 'JAMMED'
@asyncio.coroutine
def test_report_power_state(hass):
"""Test PowerController implements powerState property."""
hass.states.async_set(
'switch.on', STATE_ON, {})
hass.states.async_set(
'switch.off', STATE_OFF, {})
request = get_new_request('Alexa', 'ReportState', 'switch#on')
msg = yield from smart_home.async_handle_message(
hass, DEFAULT_CONFIG, request)
yield from hass.async_block_till_done()
properties = msg['context']['properties']
assert len(properties) == 1
prop = properties[0]
assert prop['namespace'] == 'Alexa.PowerController'
assert prop['name'] == 'powerState'
assert prop['value'] == 'ON'
request = get_new_request('Alexa', 'ReportState', 'switch#off')
msg = yield from smart_home.async_handle_message(
hass, DEFAULT_CONFIG, request)
yield from hass.async_block_till_done()
@asyncio.coroutine
def test_report_brightness(hass):
"""Test BrightnessController implements brightness property."""
hass.states.async_set(
'light.test', STATE_ON, {
'brightness': 128,
'supported_features': light.SUPPORT_BRIGHTNESS,
}
)
request = get_new_request('Alexa', 'ReportState', 'light.test')
msg = yield from smart_home.async_handle_message(
hass, DEFAULT_CONFIG, request)
yield from hass.async_block_till_done()
for prop in msg['context']['properties']:
if (
prop['namespace'] == 'Alexa.BrightnessController'
and prop['name'] == 'brightness'
):
assert prop['value'] == 50
break
else:
assert False, 'no brightness property present'
@asyncio.coroutine
def test_entity_config(hass):
"""Test that we can configure things via entity config."""