Alexa improvements (#10632)

* Initial scene support

* Initial fan support

* ordering

* Initial lock support

* Scenes cant be deactivated; Correct the scene display category

* Initial input_boolean support

* Support customization of Alexa discovered entities

* Initial media player support

* Add input_boolean to tests

* Add play/pause/stop/next/previous to media player

* Add missing functions and pylint

* Set manufacturerName to Home Assistant since the value is displayed in app

* Add scene test

* Add fan tests

* Add lock test

* Fix volume logic

* Add volume tests

* settup -> setup

* Remove unused variable

* Set required scene description as per docs

* Allow setting scene category (ACTIVITY_TRIGGER/SCENE_TRIGGER)

* Add alert, automation and group support/tests

* Change display categories to match docs

* simplify down the display category props into a single prop which can be used on any entity

* Fix tests to expect proper display categories

* Add cover support

* sort things

* Use generic homeassistant domain for turn on/off
This commit is contained in:
Robbie Trencheny 2017-11-17 09:14:22 -08:00 committed by Paulus Schoutsen
parent bf8e2bd77e
commit e449ceeeff
2 changed files with 853 additions and 27 deletions

View file

@ -4,9 +4,16 @@ import logging
import math
from uuid import uuid4
import homeassistant.core as ha
from homeassistant.const import (
ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF)
from homeassistant.components import switch, light, script
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, SERVICE_LOCK,
SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY,
SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_STOP,
SERVICE_SET_COVER_POSITION, SERVICE_TURN_OFF, SERVICE_TURN_ON,
SERVICE_UNLOCK, SERVICE_VOLUME_SET)
from homeassistant.components import (
alert, automation, cover, fan, group, input_boolean, light, lock,
media_player, scene, script, switch)
import homeassistant.util.color as color_util
from homeassistant.util.decorator import Registry
@ -14,15 +21,32 @@ HANDLERS = Registry()
_LOGGER = logging.getLogger(__name__)
API_DIRECTIVE = 'directive'
API_ENDPOINT = 'endpoint'
API_EVENT = 'event'
API_HEADER = 'header'
API_PAYLOAD = 'payload'
API_ENDPOINT = 'endpoint'
ATTR_ALEXA_DESCRIPTION = 'alexa_description'
ATTR_ALEXA_DISPLAY_CATEGORIES = 'alexa_display_categories'
ATTR_ALEXA_HIDDEN = 'alexa_hidden'
ATTR_ALEXA_NAME = 'alexa_name'
MAPPING_COMPONENT = {
script.DOMAIN: ['SWITCH', ('Alexa.PowerController',), None],
switch.DOMAIN: ['SWITCH', ('Alexa.PowerController',), None],
alert.DOMAIN: ['OTHER', ('Alexa.PowerController',), None],
automation.DOMAIN: ['OTHER', ('Alexa.PowerController',), None],
cover.DOMAIN: [
'DOOR', ('Alexa.PowerController',), {
cover.SUPPORT_SET_POSITION: 'Alexa.PercentageController',
}
],
fan.DOMAIN: [
'OTHER', ('Alexa.PowerController',), {
fan.SUPPORT_SET_SPEED: 'Alexa.PercentageController',
}
],
group.DOMAIN: ['OTHER', ('Alexa.PowerController',), None],
input_boolean.DOMAIN: ['OTHER', ('Alexa.PowerController',), None],
light.DOMAIN: [
'LIGHT', ('Alexa.PowerController',), {
light.SUPPORT_BRIGHTNESS: 'Alexa.BrightnessController',
@ -31,6 +55,20 @@ MAPPING_COMPONENT = {
light.SUPPORT_COLOR_TEMP: 'Alexa.ColorTemperatureController',
}
],
lock.DOMAIN: ['SMARTLOCK', ('Alexa.LockController',), None],
media_player.DOMAIN: [
'TV', ('Alexa.PowerController',), {
media_player.SUPPORT_VOLUME_SET: 'Alexa.Speaker',
media_player.SUPPORT_PLAY: 'Alexa.PlaybackController',
media_player.SUPPORT_PAUSE: 'Alexa.PlaybackController',
media_player.SUPPORT_STOP: 'Alexa.PlaybackController',
media_player.SUPPORT_NEXT_TRACK: 'Alexa.PlaybackController',
media_player.SUPPORT_PREVIOUS_TRACK: 'Alexa.PlaybackController',
}
],
scene.DOMAIN: ['ACTIVITY_TRIGGER', ('Alexa.SceneController',), None],
script.DOMAIN: ['OTHER', ('Alexa.PowerController',), None],
switch.DOMAIN: ['SWITCH', ('Alexa.PowerController',), None],
}
@ -108,18 +146,33 @@ def async_api_discovery(hass, request):
discovery_endpoints = []
for entity in hass.states.async_all():
if entity.attributes.get(ATTR_ALEXA_HIDDEN, False):
continue
class_data = MAPPING_COMPONENT.get(entity.domain)
if not class_data:
continue
friendly_name = entity.attributes.get(ATTR_ALEXA_NAME, entity.name)
description = entity.attributes.get(ATTR_ALEXA_DESCRIPTION,
entity.entity_id)
# Required description as per Amazon Scene docs
if entity.domain == scene.DOMAIN:
scene_fmt = '%s (Scene connected via Home Assistant)'
description = scene_fmt.format(description)
cat_key = ATTR_ALEXA_DISPLAY_CATEGORIES
display_categories = entity.attributes.get(cat_key, class_data[0])
endpoint = {
'displayCategories': [class_data[0]],
'displayCategories': [display_categories],
'additionalApplianceDetails': {},
'endpointId': entity.entity_id.replace('.', '#'),
'friendlyName': entity.name,
'description': '',
'manufacturerName': 'Unknown',
'friendlyName': friendly_name,
'description': description,
'manufacturerName': 'Home Assistant',
}
actions = set()
@ -175,7 +228,7 @@ def extract_entity(funct):
@asyncio.coroutine
def async_api_turn_on(hass, request, entity):
"""Process a turn on request."""
yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
yield from hass.services.async_call(ha.DOMAIN, SERVICE_TURN_ON, {
ATTR_ENTITY_ID: entity.entity_id
}, blocking=True)
@ -187,7 +240,7 @@ def async_api_turn_on(hass, request, entity):
@asyncio.coroutine
def async_api_turn_off(hass, request, entity):
"""Process a turn off request."""
yield from hass.services.async_call(entity.domain, SERVICE_TURN_OFF, {
yield from hass.services.async_call(ha.DOMAIN, SERVICE_TURN_OFF, {
ATTR_ENTITY_ID: entity.entity_id
}, blocking=True)
@ -310,3 +363,262 @@ def async_api_increase_color_temp(hass, request, entity):
}, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.SceneController', 'Activate'))
@extract_entity
@asyncio.coroutine
def async_api_activate(hass, request, entity):
"""Process a activate request."""
yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
ATTR_ENTITY_ID: entity.entity_id
}, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PercentageController', 'SetPercentage'))
@extract_entity
@asyncio.coroutine
def async_api_set_percentage(hass, request, entity):
"""Process a set percentage request."""
percentage = int(request[API_PAYLOAD]['percentage'])
service = None
data = {ATTR_ENTITY_ID: entity.entity_id}
if entity.domain == fan.DOMAIN:
service = fan.SERVICE_SET_SPEED
speed = "off"
if percentage <= 33:
speed = "low"
elif percentage <= 66:
speed = "medium"
elif percentage <= 100:
speed = "high"
data[fan.ATTR_SPEED] = speed
elif entity.domain == cover.DOMAIN:
service = SERVICE_SET_COVER_POSITION
data[cover.ATTR_POSITION] = percentage
yield from hass.services.async_call(entity.domain, service,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PercentageController', 'AdjustPercentage'))
@extract_entity
@asyncio.coroutine
def async_api_adjust_percentage(hass, request, entity):
"""Process a adjust percentage request."""
percentage_delta = int(request[API_PAYLOAD]['percentageDelta'])
service = None
data = {ATTR_ENTITY_ID: entity.entity_id}
if entity.domain == fan.DOMAIN:
service = fan.SERVICE_SET_SPEED
speed = entity.attributes.get(fan.ATTR_SPEED)
if speed == "off":
current = 0
elif speed == "low":
current = 33
elif speed == "medium":
current = 66
elif speed == "high":
current = 100
# set percentage
percentage = max(0, percentage_delta + current)
speed = "off"
if percentage <= 33:
speed = "low"
elif percentage <= 66:
speed = "medium"
elif percentage <= 100:
speed = "high"
data[fan.ATTR_SPEED] = speed
elif entity.domain == cover.DOMAIN:
service = SERVICE_SET_COVER_POSITION
current = entity.attributes.get(cover.ATTR_POSITION)
data[cover.ATTR_POSITION] = max(0, percentage_delta + current)
yield from hass.services.async_call(entity.domain, service,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.LockController', 'Lock'))
@extract_entity
@asyncio.coroutine
def async_api_lock(hass, request, entity):
"""Process a lock request."""
yield from hass.services.async_call(entity.domain, SERVICE_LOCK, {
ATTR_ENTITY_ID: entity.entity_id
}, blocking=True)
return api_message(request)
# Not supported by Alexa yet
@HANDLERS.register(('Alexa.LockController', 'Unlock'))
@extract_entity
@asyncio.coroutine
def async_api_unlock(hass, request, entity):
"""Process a unlock request."""
yield from hass.services.async_call(entity.domain, SERVICE_UNLOCK, {
ATTR_ENTITY_ID: entity.entity_id
}, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.Speaker', 'SetVolume'))
@extract_entity
@asyncio.coroutine
def async_api_set_volume(hass, request, entity):
"""Process a set volume request."""
volume = round(float(request[API_PAYLOAD]['volume'] / 100), 2)
data = {
ATTR_ENTITY_ID: entity.entity_id,
media_player.ATTR_MEDIA_VOLUME_LEVEL: volume,
}
yield from hass.services.async_call(entity.domain, SERVICE_VOLUME_SET,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.Speaker', 'AdjustVolume'))
@extract_entity
@asyncio.coroutine
def async_api_adjust_volume(hass, request, entity):
"""Process a adjust volume request."""
volume_delta = int(request[API_PAYLOAD]['volume'])
current_level = entity.attributes.get(media_player.ATTR_MEDIA_VOLUME_LEVEL)
# read current state
try:
current = math.floor(int(current_level * 100))
except ZeroDivisionError:
current = 0
volume = float(max(0, volume_delta + current) / 100)
data = {
ATTR_ENTITY_ID: entity.entity_id,
media_player.ATTR_MEDIA_VOLUME_LEVEL: volume,
}
yield from hass.services.async_call(entity.domain,
media_player.SERVICE_VOLUME_SET,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.Speaker', 'SetMute'))
@extract_entity
@asyncio.coroutine
def async_api_set_mute(hass, request, entity):
"""Process a set mute request."""
mute = bool(request[API_PAYLOAD]['mute'])
data = {
ATTR_ENTITY_ID: entity.entity_id,
media_player.ATTR_MEDIA_VOLUME_MUTED: mute,
}
yield from hass.services.async_call(entity.domain,
media_player.SERVICE_VOLUME_MUTE,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PlaybackController', 'Play'))
@extract_entity
@asyncio.coroutine
def async_api_play(hass, request, entity):
"""Process a play request."""
data = {
ATTR_ENTITY_ID: entity.entity_id
}
yield from hass.services.async_call(entity.domain, SERVICE_MEDIA_PLAY,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PlaybackController', 'Pause'))
@extract_entity
@asyncio.coroutine
def async_api_pause(hass, request, entity):
"""Process a pause request."""
data = {
ATTR_ENTITY_ID: entity.entity_id
}
yield from hass.services.async_call(entity.domain, SERVICE_MEDIA_PAUSE,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PlaybackController', 'Stop'))
@extract_entity
@asyncio.coroutine
def async_api_stop(hass, request, entity):
"""Process a stop request."""
data = {
ATTR_ENTITY_ID: entity.entity_id
}
yield from hass.services.async_call(entity.domain, SERVICE_MEDIA_STOP,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PlaybackController', 'Next'))
@extract_entity
@asyncio.coroutine
def async_api_next(hass, request, entity):
"""Process a next request."""
data = {
ATTR_ENTITY_ID: entity.entity_id
}
yield from hass.services.async_call(entity.domain,
SERVICE_MEDIA_NEXT_TRACK,
data, blocking=True)
return api_message(request)
@HANDLERS.register(('Alexa.PlaybackController', 'Previous'))
@extract_entity
@asyncio.coroutine
def async_api_previous(hass, request, entity):
"""Process a previous request."""
data = {
ATTR_ENTITY_ID: entity.entity_id
}
yield from hass.services.async_call(entity.domain,
SERVICE_MEDIA_PREVIOUS_TRACK,
data, blocking=True)
return api_message(request)

View file

@ -99,7 +99,7 @@ def test_discovery_request(hass):
"""Test alexa discovery request."""
request = get_new_request('Alexa.Discovery', 'Discover')
# settup test devices
# setup test devices
hass.states.async_set(
'switch.test', 'on', {'friendly_name': "Test switch"})
@ -117,12 +117,52 @@ def test_discovery_request(hass):
hass.states.async_set(
'script.test', 'off', {'friendly_name': "Test script"})
hass.states.async_set(
'input_boolean.test', 'off', {'friendly_name': "Test input boolean"})
hass.states.async_set(
'scene.test', 'off', {'friendly_name': "Test scene"})
hass.states.async_set(
'fan.test_1', 'off', {'friendly_name': "Test fan 1"})
hass.states.async_set(
'fan.test_2', 'off', {
'friendly_name': "Test fan 2", 'supported_features': 1,
'speed_list': ['low', 'medium', 'high']
})
hass.states.async_set(
'lock.test', 'off', {'friendly_name': "Test lock"})
hass.states.async_set(
'media_player.test', 'off', {
'friendly_name': "Test media player",
'supported_features': 20925,
'volume_level': 1
})
hass.states.async_set(
'alert.test', 'off', {'friendly_name': "Test alert"})
hass.states.async_set(
'automation.test', 'off', {'friendly_name': "Test automation"})
hass.states.async_set(
'group.test', 'off', {'friendly_name': "Test group"})
hass.states.async_set(
'cover.test', 'off', {
'friendly_name': "Test cover", 'supported_features': 255,
'position': 85
})
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(msg['payload']['endpoints']) == 5
assert len(msg['payload']['endpoints']) == 15
assert msg['header']['name'] == 'Discover.Response'
assert msg['header']['namespace'] == 'Alexa.Discovery'
@ -174,13 +214,108 @@ def test_discovery_request(hass):
continue
if appliance['endpointId'] == 'script#test':
assert appliance['displayCategories'][0] == "SWITCH"
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test script"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.PowerController'
continue
if appliance['endpointId'] == 'input_boolean#test':
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test input boolean"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.PowerController'
continue
if appliance['endpointId'] == 'scene#test':
assert appliance['displayCategories'][0] == "ACTIVITY_TRIGGER"
assert appliance['friendlyName'] == "Test scene"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.SceneController'
continue
if appliance['endpointId'] == 'fan#test_1':
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test fan 1"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.PowerController'
continue
if appliance['endpointId'] == 'fan#test_2':
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test fan 2"
assert len(appliance['capabilities']) == 2
caps = set()
for feature in appliance['capabilities']:
caps.add(feature['interface'])
assert 'Alexa.PercentageController' in caps
assert 'Alexa.PowerController' in caps
continue
if appliance['endpointId'] == 'lock#test':
assert appliance['displayCategories'][0] == "SMARTLOCK"
assert appliance['friendlyName'] == "Test lock"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.LockController'
continue
if appliance['endpointId'] == 'media_player#test':
assert appliance['displayCategories'][0] == "TV"
assert appliance['friendlyName'] == "Test media player"
assert len(appliance['capabilities']) == 3
caps = set()
for feature in appliance['capabilities']:
caps.add(feature['interface'])
assert 'Alexa.PowerController' in caps
assert 'Alexa.Speaker' in caps
assert 'Alexa.PlaybackController' in caps
continue
if appliance['endpointId'] == 'alert#test':
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test alert"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.PowerController'
continue
if appliance['endpointId'] == 'automation#test':
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test automation"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.PowerController'
continue
if appliance['endpointId'] == 'group#test':
assert appliance['displayCategories'][0] == "OTHER"
assert appliance['friendlyName'] == "Test group"
assert len(appliance['capabilities']) == 1
assert appliance['capabilities'][-1]['interface'] == \
'Alexa.PowerController'
continue
if appliance['endpointId'] == 'cover#test':
assert appliance['displayCategories'][0] == "DOOR"
assert appliance['friendlyName'] == "Test cover"
assert len(appliance['capabilities']) == 2
caps = set()
for feature in appliance['capabilities']:
caps.add(feature['interface'])
assert 'Alexa.PercentageController' in caps
assert 'Alexa.PowerController' in caps
continue
raise AssertionError("Unknown appliance!")
@ -217,19 +352,21 @@ def test_api_function_not_implemented(hass):
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['light', 'switch', 'script'])
@pytest.mark.parametrize("domain", ['alert', 'automation', 'group',
'input_boolean', 'light', 'script',
'switch'])
def test_api_turn_on(hass, domain):
"""Test api turn on process."""
request = get_new_request(
'Alexa.PowerController', 'TurnOn', '{}#test'.format(domain))
# settup test devices
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'turn_on')
call = async_mock_service(hass, 'homeassistant', 'turn_on')
msg = yield from smart_home.async_handle_message(hass, request)
@ -242,19 +379,21 @@ def test_api_turn_on(hass, domain):
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['light', 'switch', 'script'])
@pytest.mark.parametrize("domain", ['alert', 'automation', 'group',
'input_boolean', 'light', 'script',
'switch'])
def test_api_turn_off(hass, domain):
"""Test api turn on process."""
request = get_new_request(
'Alexa.PowerController', 'TurnOff', '{}#test'.format(domain))
# settup test devices
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'on', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'turn_off')
call = async_mock_service(hass, 'homeassistant', 'turn_off')
msg = yield from smart_home.async_handle_message(hass, request)
@ -275,7 +414,7 @@ def test_api_set_brightness(hass):
# add payload
request['directive']['payload']['brightness'] = '50'
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {'friendly_name': "Test light"})
@ -303,7 +442,7 @@ def test_api_adjust_brightness(hass, result, adjust):
# add payload
request['directive']['payload']['brightnessDelta'] = adjust
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {
'friendly_name': "Test light", 'brightness': '77'
@ -335,7 +474,7 @@ def test_api_set_color_rgb(hass):
'brightness': '0.342',
}
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {
'friendly_name': "Test light",
@ -368,7 +507,7 @@ def test_api_set_color_xy(hass):
'brightness': '0.342',
}
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {
'friendly_name': "Test light",
@ -399,7 +538,7 @@ def test_api_set_color_temperature(hass):
# add payload
request['directive']['payload']['colorTemperatureInKelvin'] = '7500'
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {'friendly_name': "Test light"})
@ -424,7 +563,7 @@ def test_api_decrease_color_temp(hass, result, initial):
'Alexa.ColorTemperatureController', 'DecreaseColorTemperature',
'light#test')
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {
'friendly_name': "Test light", 'color_temp': initial,
@ -452,7 +591,7 @@ def test_api_increase_color_temp(hass, result, initial):
'Alexa.ColorTemperatureController', 'IncreaseColorTemperature',
'light#test')
# settup test devices
# setup test devices
hass.states.async_set(
'light.test', 'off', {
'friendly_name': "Test light", 'color_temp': initial,
@ -470,3 +609,378 @@ def test_api_increase_color_temp(hass, result, initial):
assert call_light[0].data['entity_id'] == 'light.test'
assert call_light[0].data['color_temp'] == result
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['scene'])
def test_api_activate(hass, domain):
"""Test api activate process."""
request = get_new_request(
'Alexa.SceneController', 'Activate', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'turn_on')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
def test_api_set_percentage_fan(hass):
"""Test api set percentage for fan process."""
request = get_new_request(
'Alexa.PercentageController', 'SetPercentage', 'fan#test_2')
# add payload
request['directive']['payload']['percentage'] = '50'
# setup test devices
hass.states.async_set(
'fan.test_2', 'off', {'friendly_name': "Test fan"})
call_fan = async_mock_service(hass, 'fan', 'set_speed')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call_fan) == 1
assert call_fan[0].data['entity_id'] == 'fan.test_2'
assert call_fan[0].data['speed'] == 'medium'
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
def test_api_set_percentage_cover(hass):
"""Test api set percentage for cover process."""
request = get_new_request(
'Alexa.PercentageController', 'SetPercentage', 'cover#test')
# add payload
request['directive']['payload']['percentage'] = '50'
# setup test devices
hass.states.async_set(
'cover.test', 'closed', {
'friendly_name': "Test cover"
})
call_cover = async_mock_service(hass, 'cover', 'set_cover_position')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call_cover) == 1
assert call_cover[0].data['entity_id'] == 'cover.test'
assert call_cover[0].data['position'] == 50
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize(
"result,adjust", [('high', '-5'), ('off', '5'), ('low', '-80')])
def test_api_adjust_percentage_fan(hass, result, adjust):
"""Test api adjust percentage for fan process."""
request = get_new_request(
'Alexa.PercentageController', 'AdjustPercentage', 'fan#test_2')
# add payload
request['directive']['payload']['percentageDelta'] = adjust
# setup test devices
hass.states.async_set(
'fan.test_2', 'on', {
'friendly_name': "Test fan 2", 'speed': 'high'
})
call_fan = async_mock_service(hass, 'fan', 'set_speed')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call_fan) == 1
assert call_fan[0].data['entity_id'] == 'fan.test_2'
assert call_fan[0].data['speed'] == result
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize(
"result,adjust", [(25, '-5'), (35, '5'), (0, '-80')])
def test_api_adjust_percentage_cover(hass, result, adjust):
"""Test api adjust percentage for cover process."""
request = get_new_request(
'Alexa.PercentageController', 'AdjustPercentage', 'cover#test')
# add payload
request['directive']['payload']['percentageDelta'] = adjust
# setup test devices
hass.states.async_set(
'cover.test', 'closed', {
'friendly_name': "Test cover",
'position': 30
})
call_cover = async_mock_service(hass, 'cover', 'set_cover_position')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call_cover) == 1
assert call_cover[0].data['entity_id'] == 'cover.test'
assert call_cover[0].data['position'] == result
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['lock'])
def test_api_lock(hass, domain):
"""Test api lock process."""
request = get_new_request(
'Alexa.LockController', 'Lock', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'lock')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['media_player'])
def test_api_play(hass, domain):
"""Test api play process."""
request = get_new_request(
'Alexa.PlaybackController', 'Play', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'media_play')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['media_player'])
def test_api_pause(hass, domain):
"""Test api pause process."""
request = get_new_request(
'Alexa.PlaybackController', 'Pause', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'media_pause')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['media_player'])
def test_api_stop(hass, domain):
"""Test api stop process."""
request = get_new_request(
'Alexa.PlaybackController', 'Stop', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'media_stop')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['media_player'])
def test_api_next(hass, domain):
"""Test api next process."""
request = get_new_request(
'Alexa.PlaybackController', 'Next', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'media_next_track')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['media_player'])
def test_api_previous(hass, domain):
"""Test api previous process."""
request = get_new_request(
'Alexa.PlaybackController', 'Previous', '{}#test'.format(domain))
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'media_previous_track')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
def test_api_set_volume(hass):
"""Test api set volume process."""
request = get_new_request(
'Alexa.Speaker', 'SetVolume', 'media_player#test')
# add payload
request['directive']['payload']['volume'] = 50
# setup test devices
hass.states.async_set(
'media_player.test', 'off', {
'friendly_name': "Test media player", 'volume_level': 0
})
call_media_player = async_mock_service(hass, 'media_player', 'volume_set')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call_media_player) == 1
assert call_media_player[0].data['entity_id'] == 'media_player.test'
assert call_media_player[0].data['volume_level'] == 0.5
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize(
"result,adjust", [(0.7, '-5'), (0.8, '5'), (0, '-80')])
def test_api_adjust_volume(hass, result, adjust):
"""Test api adjust volume process."""
request = get_new_request(
'Alexa.Speaker', 'AdjustVolume', 'media_player#test')
# add payload
request['directive']['payload']['volume'] = adjust
# setup test devices
hass.states.async_set(
'media_player.test', 'off', {
'friendly_name': "Test media player", 'volume_level': 0.75
})
call_media_player = async_mock_service(hass, 'media_player', 'volume_set')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call_media_player) == 1
assert call_media_player[0].data['entity_id'] == 'media_player.test'
assert call_media_player[0].data['volume_level'] == result
assert msg['header']['name'] == 'Response'
@asyncio.coroutine
@pytest.mark.parametrize("domain", ['media_player'])
def test_api_mute(hass, domain):
"""Test api mute process."""
request = get_new_request(
'Alexa.Speaker', 'SetMute', '{}#test'.format(domain))
request['directive']['payload']['mute'] = True
# setup test devices
hass.states.async_set(
'{}.test'.format(domain), 'off', {
'friendly_name': "Test {}".format(domain)
})
call = async_mock_service(hass, domain, 'volume_mute')
msg = yield from smart_home.async_handle_message(hass, request)
assert 'event' in msg
msg = msg['event']
assert len(call) == 1
assert call[0].data['entity_id'] == '{}.test'.format(domain)
assert msg['header']['name'] == 'Response'