diff --git a/homeassistant/components/alexa/smart_home.py b/homeassistant/components/alexa/smart_home.py index e09ee751e43..6721c0038e8 100644 --- a/homeassistant/components/alexa/smart_home.py +++ b/homeassistant/components/alexa/smart_home.py @@ -17,7 +17,7 @@ from homeassistant.const import ( SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_STOP, SERVICE_SET_COVER_POSITION, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_UNLOCK, SERVICE_VOLUME_SET, TEMP_FAHRENHEIT, TEMP_CELSIUS, - CONF_UNIT_OF_MEASUREMENT) + CONF_UNIT_OF_MEASUREMENT, STATE_LOCKED, STATE_UNLOCKED, STATE_ON) from .const import CONF_FILTER, CONF_ENTITY_CONFIG _LOGGER = logging.getLogger(__name__) @@ -245,9 +245,8 @@ class _AlexaInterface(object): 'properties': { 'supported': self.properties_supported(), 'proactivelyReported': self.properties_proactively_reported(), + 'retrievable': self.properties_retrievable(), }, - # XXX this is incorrect, but the tests assert it - 'retrievable': self.properties_retrievable(), } # pylint: disable=assignment-from-none @@ -271,11 +270,41 @@ class _AlexaPowerController(_AlexaInterface): def name(self): return 'Alexa.PowerController' + def properties_supported(self): + return [{'name': 'powerState'}] + + def properties_retrievable(self): + return True + + def get_property(self, name): + if name != 'powerState': + raise _UnsupportedProperty(name) + + if self.entity.state == STATE_ON: + return 'ON' + return 'OFF' + class _AlexaLockController(_AlexaInterface): def name(self): return 'Alexa.LockController' + def properties_supported(self): + return [{'name': 'lockState'}] + + def properties_retrievable(self): + return True + + def get_property(self, name): + if name != 'lockState': + raise _UnsupportedProperty(name) + + if self.entity.state == STATE_LOCKED: + return 'LOCKED' + elif self.entity.state == STATE_UNLOCKED: + return 'UNLOCKED' + return 'JAMMED' + class _AlexaSceneController(_AlexaInterface): def __init__(self, entity, supports_deactivation): @@ -290,6 +319,18 @@ class _AlexaBrightnessController(_AlexaInterface): def name(self): return 'Alexa.BrightnessController' + def properties_supported(self): + return [{'name': 'brightness'}] + + def properties_retrievable(self): + return True + + def get_property(self, name): + if name != 'brightness': + raise _UnsupportedProperty(name) + + return round(self.entity.attributes['brightness'] / 255.0 * 100) + class _AlexaColorController(_AlexaInterface): def name(self): diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index 1b2e98d6558..7795bc85f1a 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -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."""