Rewrite Alexa Smart-Home skill to v3 (#9699)
* Rewrite Alexa Smart-Home skill to v3 * add discovery & fix brigness * Rewrite Tests * fix lint * fix lint p2 * fix version * fix tests * fix test message generator * Update smart_home.py * fix test * fix set bug * fix list * fix response name for discovery * fix flucky tests
This commit is contained in:
parent
4342d7aa17
commit
c1f156fd2b
2 changed files with 237 additions and 119 deletions
|
@ -11,19 +11,18 @@ from homeassistant.util.decorator import Registry
|
||||||
HANDLERS = Registry()
|
HANDLERS = Registry()
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ATTR_HEADER = 'header'
|
API_DIRECTIVE = 'directive'
|
||||||
ATTR_NAME = 'name'
|
API_EVENT = 'event'
|
||||||
ATTR_NAMESPACE = 'namespace'
|
API_HEADER = 'header'
|
||||||
ATTR_MESSAGE_ID = 'messageId'
|
API_PAYLOAD = 'payload'
|
||||||
ATTR_PAYLOAD = 'payload'
|
API_ENDPOINT = 'endpoint'
|
||||||
ATTR_PAYLOAD_VERSION = 'payloadVersion'
|
|
||||||
|
|
||||||
|
|
||||||
MAPPING_COMPONENT = {
|
MAPPING_COMPONENT = {
|
||||||
switch.DOMAIN: ['SWITCH', ('turnOff', 'turnOn'), None],
|
switch.DOMAIN: ['SWITCH', ('Alexa.PowerController',), None],
|
||||||
light.DOMAIN: [
|
light.DOMAIN: [
|
||||||
'LIGHT', ('turnOff', 'turnOn'), {
|
'LIGHT', ('Alexa.PowerController',), {
|
||||||
light.SUPPORT_BRIGHTNESS: 'setPercentage'
|
light.SUPPORT_BRIGHTNESS: 'Alexa.BrightnessController'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -32,51 +31,75 @@ MAPPING_COMPONENT = {
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_handle_message(hass, message):
|
def async_handle_message(hass, message):
|
||||||
"""Handle incoming API messages."""
|
"""Handle incoming API messages."""
|
||||||
assert int(message[ATTR_HEADER][ATTR_PAYLOAD_VERSION]) == 2
|
assert message[API_DIRECTIVE][API_HEADER]['payloadVersion'] == '3'
|
||||||
|
|
||||||
|
# Read head data
|
||||||
|
message = message[API_DIRECTIVE]
|
||||||
|
namespace = message[API_HEADER]['namespace']
|
||||||
|
name = message[API_HEADER]['name']
|
||||||
|
|
||||||
# Do we support this API request?
|
# Do we support this API request?
|
||||||
funct_ref = HANDLERS.get(message[ATTR_HEADER][ATTR_NAME])
|
funct_ref = HANDLERS.get((namespace, name))
|
||||||
if not funct_ref:
|
if not funct_ref:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Unsupported API request %s", message[ATTR_HEADER][ATTR_NAME])
|
"Unsupported API request %s/%s", namespace, name)
|
||||||
return api_error(message)
|
return api_error(message)
|
||||||
|
|
||||||
return (yield from funct_ref(hass, message))
|
return (yield from funct_ref(hass, message))
|
||||||
|
|
||||||
|
|
||||||
def api_message(name, namespace, payload=None):
|
def api_message(request, name='Response', namespace='Alexa', payload=None):
|
||||||
"""Create a API formatted response message.
|
"""Create a API formatted response message.
|
||||||
|
|
||||||
Async friendly.
|
Async friendly.
|
||||||
"""
|
"""
|
||||||
payload = payload or {}
|
payload = payload or {}
|
||||||
return {
|
|
||||||
ATTR_HEADER: {
|
response = {
|
||||||
ATTR_MESSAGE_ID: str(uuid4()),
|
API_EVENT: {
|
||||||
ATTR_NAME: name,
|
API_HEADER: {
|
||||||
ATTR_NAMESPACE: namespace,
|
'namespace': namespace,
|
||||||
ATTR_PAYLOAD_VERSION: '2',
|
'name': name,
|
||||||
},
|
'messageId': str(uuid4()),
|
||||||
ATTR_PAYLOAD: payload,
|
'payloadVersion': '3',
|
||||||
|
},
|
||||||
|
API_PAYLOAD: payload,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# If a correlation token exsits, add it to header / Need by Async requests
|
||||||
|
token = request[API_HEADER].get('correlationToken')
|
||||||
|
if token:
|
||||||
|
response[API_EVENT][API_HEADER]['correlationToken'] = token
|
||||||
|
|
||||||
def api_error(request, exc='DriverInternalError'):
|
# Extend event with endpoint object / Need by Async requests
|
||||||
|
if API_ENDPOINT in request:
|
||||||
|
response[API_EVENT][API_ENDPOINT] = request[API_ENDPOINT].copy()
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def api_error(request, error_type='INTERNAL_ERROR', error_message=""):
|
||||||
"""Create a API formatted error response.
|
"""Create a API formatted error response.
|
||||||
|
|
||||||
Async friendly.
|
Async friendly.
|
||||||
"""
|
"""
|
||||||
return api_message(exc, request[ATTR_HEADER][ATTR_NAMESPACE])
|
payload = {
|
||||||
|
'type': error_type,
|
||||||
|
'message': error_message,
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_message(request, name='ErrorResponse', payload=payload)
|
||||||
|
|
||||||
|
|
||||||
@HANDLERS.register('DiscoverAppliancesRequest')
|
@HANDLERS.register(('Alexa.Discovery', 'Discover'))
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_api_discovery(hass, request):
|
def async_api_discovery(hass, request):
|
||||||
"""Create a API formatted discovery response.
|
"""Create a API formatted discovery response.
|
||||||
|
|
||||||
Async friendly.
|
Async friendly.
|
||||||
"""
|
"""
|
||||||
discovered_appliances = []
|
discovery_endpoints = []
|
||||||
|
|
||||||
for entity in hass.states.async_all():
|
for entity in hass.states.async_all():
|
||||||
class_data = MAPPING_COMPONENT.get(entity.domain)
|
class_data = MAPPING_COMPONENT.get(entity.domain)
|
||||||
|
@ -84,35 +107,42 @@ def async_api_discovery(hass, request):
|
||||||
if not class_data:
|
if not class_data:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
appliance = {
|
endpoint = {
|
||||||
'actions': [],
|
'displayCategories': [class_data[0]],
|
||||||
'applianceTypes': [class_data[0]],
|
|
||||||
'additionalApplianceDetails': {},
|
'additionalApplianceDetails': {},
|
||||||
'applianceId': entity.entity_id.replace('.', '#'),
|
'endpointId': entity.entity_id.replace('.', '#'),
|
||||||
'friendlyDescription': '',
|
|
||||||
'friendlyName': entity.name,
|
'friendlyName': entity.name,
|
||||||
'isReachable': True,
|
'description': '',
|
||||||
'manufacturerName': 'Unknown',
|
'manufacturerName': 'Unknown',
|
||||||
'modelName': 'Unknown',
|
|
||||||
'version': 'Unknown',
|
|
||||||
}
|
}
|
||||||
|
actions = set()
|
||||||
|
|
||||||
# static actions
|
# static actions
|
||||||
if class_data[1]:
|
if class_data[1]:
|
||||||
appliance['actions'].extend(list(class_data[1]))
|
actions |= set(class_data[1])
|
||||||
|
|
||||||
# dynamic actions
|
# dynamic actions
|
||||||
if class_data[2]:
|
if class_data[2]:
|
||||||
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
for feature, action_name in class_data[2].items():
|
for feature, action_name in class_data[2].items():
|
||||||
if feature & supported > 0:
|
if feature & supported > 0:
|
||||||
appliance['actions'].append(action_name)
|
actions.add(action_name)
|
||||||
|
|
||||||
discovered_appliances.append(appliance)
|
# Write action into capabilities
|
||||||
|
capabilities = []
|
||||||
|
for action in actions:
|
||||||
|
capabilities.append({
|
||||||
|
'type': 'AlexaInterface',
|
||||||
|
'interface': action,
|
||||||
|
'version': 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
endpoint['capabilities'] = capabilities
|
||||||
|
discovery_endpoints.append(endpoint)
|
||||||
|
|
||||||
return api_message(
|
return api_message(
|
||||||
'DiscoverAppliancesResponse', 'Alexa.ConnectedHome.Discovery',
|
request, name='Discover.Response', namespace='Alexa.Discovery',
|
||||||
payload={'discoveredAppliances': discovered_appliances})
|
payload={'endpoints': discovery_endpoints})
|
||||||
|
|
||||||
|
|
||||||
def extract_entity(funct):
|
def extract_entity(funct):
|
||||||
|
@ -120,22 +150,21 @@ def extract_entity(funct):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_api_entity_wrapper(hass, request):
|
def async_api_entity_wrapper(hass, request):
|
||||||
"""Process a turn on request."""
|
"""Process a turn on request."""
|
||||||
entity_id = \
|
entity_id = request[API_ENDPOINT]['endpointId'].replace('#', '.')
|
||||||
request[ATTR_PAYLOAD]['appliance']['applianceId'].replace('#', '.')
|
|
||||||
|
|
||||||
# extract state object
|
# extract state object
|
||||||
entity = hass.states.get(entity_id)
|
entity = hass.states.get(entity_id)
|
||||||
if not entity:
|
if not entity:
|
||||||
_LOGGER.error("Can't process %s for %s",
|
_LOGGER.error("Can't process %s for %s",
|
||||||
request[ATTR_HEADER][ATTR_NAME], entity_id)
|
request[API_HEADER]['name'], entity_id)
|
||||||
return api_error(request)
|
return api_error(request, error_type='NO_SUCH_ENDPOINT')
|
||||||
|
|
||||||
return (yield from funct(hass, request, entity))
|
return (yield from funct(hass, request, entity))
|
||||||
|
|
||||||
return async_api_entity_wrapper
|
return async_api_entity_wrapper
|
||||||
|
|
||||||
|
|
||||||
@HANDLERS.register('TurnOnRequest')
|
@HANDLERS.register(('Alexa.PowerController', 'TurnOn'))
|
||||||
@extract_entity
|
@extract_entity
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_api_turn_on(hass, request, entity):
|
def async_api_turn_on(hass, request, entity):
|
||||||
|
@ -144,10 +173,10 @@ def async_api_turn_on(hass, request, entity):
|
||||||
ATTR_ENTITY_ID: entity.entity_id
|
ATTR_ENTITY_ID: entity.entity_id
|
||||||
}, blocking=True)
|
}, blocking=True)
|
||||||
|
|
||||||
return api_message('TurnOnConfirmation', 'Alexa.ConnectedHome.Control')
|
return api_message(request)
|
||||||
|
|
||||||
|
|
||||||
@HANDLERS.register('TurnOffRequest')
|
@HANDLERS.register(('Alexa.PowerController', 'TurnOff'))
|
||||||
@extract_entity
|
@extract_entity
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_api_turn_off(hass, request, entity):
|
def async_api_turn_off(hass, request, entity):
|
||||||
|
@ -156,22 +185,19 @@ def async_api_turn_off(hass, request, entity):
|
||||||
ATTR_ENTITY_ID: entity.entity_id
|
ATTR_ENTITY_ID: entity.entity_id
|
||||||
}, blocking=True)
|
}, blocking=True)
|
||||||
|
|
||||||
return api_message('TurnOffConfirmation', 'Alexa.ConnectedHome.Control')
|
return api_message(request)
|
||||||
|
|
||||||
|
|
||||||
@HANDLERS.register('SetPercentageRequest')
|
@HANDLERS.register(('Alexa.BrightnessController', 'SetBrightness'))
|
||||||
@extract_entity
|
@extract_entity
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_api_set_percentage(hass, request, entity):
|
def async_api_set_brightness(hass, request, entity):
|
||||||
"""Process a set percentage request."""
|
"""Process a set brightness request."""
|
||||||
if entity.domain == light.DOMAIN:
|
brightness = request[API_PAYLOAD]['brightness']
|
||||||
brightness = request[ATTR_PAYLOAD]['percentageState']['value']
|
|
||||||
yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
|
|
||||||
ATTR_ENTITY_ID: entity.entity_id,
|
|
||||||
light.ATTR_BRIGHTNESS: brightness,
|
|
||||||
}, blocking=True)
|
|
||||||
else:
|
|
||||||
return api_error(request)
|
|
||||||
|
|
||||||
return api_message(
|
yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
|
||||||
'SetPercentageConfirmation', 'Alexa.ConnectedHome.Control')
|
ATTR_ENTITY_ID: entity.entity_id,
|
||||||
|
light.ATTR_BRIGHTNESS: brightness,
|
||||||
|
}, blocking=True)
|
||||||
|
|
||||||
|
return api_message(request)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Test for smart home alexa support."""
|
"""Test for smart home alexa support."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -8,22 +9,86 @@ from homeassistant.components.alexa import smart_home
|
||||||
from tests.common import async_mock_service
|
from tests.common import async_mock_service
|
||||||
|
|
||||||
|
|
||||||
def test_create_api_message():
|
def get_new_request(namespace, name, endpoint=None):
|
||||||
"""Create a API message."""
|
"""Generate a new API message."""
|
||||||
msg = smart_home.api_message('testName', 'testNameSpace')
|
raw_msg = {
|
||||||
|
'directive': {
|
||||||
|
'header': {
|
||||||
|
'namespace': namespace,
|
||||||
|
'name': name,
|
||||||
|
'messageId': str(uuid4()),
|
||||||
|
'correlationToken': str(uuid4()),
|
||||||
|
'payloadVersion': '3',
|
||||||
|
},
|
||||||
|
'endpoint': {
|
||||||
|
'scope': {
|
||||||
|
'type': 'BearerToken',
|
||||||
|
'token': str(uuid4()),
|
||||||
|
},
|
||||||
|
'endpointId': endpoint,
|
||||||
|
},
|
||||||
|
'payload': {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if not endpoint:
|
||||||
|
raw_msg['directive'].pop('endpoint')
|
||||||
|
|
||||||
|
return raw_msg
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_api_message_defaults():
|
||||||
|
"""Create a API message response of a request with defaults."""
|
||||||
|
request = get_new_request('Alexa.PowerController', 'TurnOn', 'switch#xy')
|
||||||
|
request = request['directive']
|
||||||
|
|
||||||
|
msg = smart_home.api_message(request, payload={'test': 3})
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
assert msg['header']['messageId'] is not None
|
assert msg['header']['messageId'] is not None
|
||||||
|
assert msg['header']['messageId'] != request['header']['messageId']
|
||||||
|
assert msg['header']['correlationToken'] == \
|
||||||
|
request['header']['correlationToken']
|
||||||
|
assert msg['header']['name'] == 'Response'
|
||||||
|
assert msg['header']['namespace'] == 'Alexa'
|
||||||
|
assert msg['header']['payloadVersion'] == '3'
|
||||||
|
|
||||||
|
assert 'test' in msg['payload']
|
||||||
|
assert msg['payload']['test'] == 3
|
||||||
|
|
||||||
|
assert msg['endpoint'] == request['endpoint']
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_api_message_special():
|
||||||
|
"""Create a API message response of a request with non defaults."""
|
||||||
|
request = get_new_request('Alexa.PowerController', 'TurnOn')
|
||||||
|
request = request['directive']
|
||||||
|
|
||||||
|
request['header'].pop('correlationToken')
|
||||||
|
|
||||||
|
msg = smart_home.api_message(request, 'testName', 'testNameSpace')
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
|
assert msg['header']['messageId'] is not None
|
||||||
|
assert msg['header']['messageId'] != request['header']['messageId']
|
||||||
|
assert 'correlationToken' not in msg['header']
|
||||||
assert msg['header']['name'] == 'testName'
|
assert msg['header']['name'] == 'testName'
|
||||||
assert msg['header']['namespace'] == 'testNameSpace'
|
assert msg['header']['namespace'] == 'testNameSpace'
|
||||||
assert msg['header']['payloadVersion'] == '2'
|
assert msg['header']['payloadVersion'] == '3'
|
||||||
|
|
||||||
assert msg['payload'] == {}
|
assert msg['payload'] == {}
|
||||||
|
assert 'endpoint' not in msg
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_wrong_version(hass):
|
def test_wrong_version(hass):
|
||||||
"""Test with wrong version."""
|
"""Test with wrong version."""
|
||||||
msg = smart_home.api_message('testName', 'testNameSpace')
|
msg = get_new_request('Alexa.PowerController', 'TurnOn')
|
||||||
msg['header']['payloadVersion'] = '3'
|
msg['directive']['header']['payloadVersion'] = '2'
|
||||||
|
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
yield from smart_home.async_handle_message(hass, msg)
|
yield from smart_home.async_handle_message(hass, msg)
|
||||||
|
@ -32,8 +97,7 @@ def test_wrong_version(hass):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_discovery_request(hass):
|
def test_discovery_request(hass):
|
||||||
"""Test alexa discovery request."""
|
"""Test alexa discovery request."""
|
||||||
msg = smart_home.api_message(
|
request = get_new_request('Alexa.Discovery', 'Discover')
|
||||||
'DiscoverAppliancesRequest', 'Alexa.ConnectedHome.Discovery')
|
|
||||||
|
|
||||||
# settup test devices
|
# settup test devices
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -46,30 +110,44 @@ def test_discovery_request(hass):
|
||||||
'friendly_name': "Test light 2", 'supported_features': 1
|
'friendly_name': "Test light 2", 'supported_features': 1
|
||||||
})
|
})
|
||||||
|
|
||||||
resp = yield from smart_home.async_api_discovery(hass, msg)
|
msg = yield from smart_home.async_handle_message(hass, request)
|
||||||
|
|
||||||
assert len(resp['payload']['discoveredAppliances']) == 3
|
assert 'event' in msg
|
||||||
assert resp['header']['name'] == 'DiscoverAppliancesResponse'
|
msg = msg['event']
|
||||||
assert resp['header']['namespace'] == 'Alexa.ConnectedHome.Discovery'
|
|
||||||
|
|
||||||
for i, appliance in enumerate(resp['payload']['discoveredAppliances']):
|
assert len(msg['payload']['endpoints']) == 3
|
||||||
if appliance['applianceId'] == 'switch#test':
|
assert msg['header']['name'] == 'Discover.Response'
|
||||||
assert appliance['applianceTypes'][0] == "SWITCH"
|
assert msg['header']['namespace'] == 'Alexa.Discovery'
|
||||||
|
|
||||||
|
for appliance in msg['payload']['endpoints']:
|
||||||
|
if appliance['endpointId'] == 'switch#test':
|
||||||
|
assert appliance['displayCategories'][0] == "SWITCH"
|
||||||
assert appliance['friendlyName'] == "Test switch"
|
assert appliance['friendlyName'] == "Test switch"
|
||||||
assert appliance['actions'] == ['turnOff', 'turnOn']
|
assert len(appliance['capabilities']) == 1
|
||||||
|
assert appliance['capabilities'][-1]['interface'] == \
|
||||||
|
'Alexa.PowerController'
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if appliance['applianceId'] == 'light#test_1':
|
if appliance['endpointId'] == 'light#test_1':
|
||||||
assert appliance['applianceTypes'][0] == "LIGHT"
|
assert appliance['displayCategories'][0] == "LIGHT"
|
||||||
assert appliance['friendlyName'] == "Test light 1"
|
assert appliance['friendlyName'] == "Test light 1"
|
||||||
assert appliance['actions'] == ['turnOff', 'turnOn']
|
assert len(appliance['capabilities']) == 1
|
||||||
|
assert appliance['capabilities'][-1]['interface'] == \
|
||||||
|
'Alexa.PowerController'
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if appliance['applianceId'] == 'light#test_2':
|
if appliance['endpointId'] == 'light#test_2':
|
||||||
assert appliance['applianceTypes'][0] == "LIGHT"
|
assert appliance['displayCategories'][0] == "LIGHT"
|
||||||
assert appliance['friendlyName'] == "Test light 2"
|
assert appliance['friendlyName'] == "Test light 2"
|
||||||
assert appliance['actions'] == \
|
assert len(appliance['capabilities']) == 2
|
||||||
['turnOff', 'turnOn', 'setPercentage']
|
|
||||||
|
caps = set()
|
||||||
|
for feature in appliance['capabilities']:
|
||||||
|
caps.add(feature['interface'])
|
||||||
|
|
||||||
|
assert 'Alexa.BrightnessController' in caps
|
||||||
|
assert 'Alexa.PowerController' in caps
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise AssertionError("Unknown appliance!")
|
raise AssertionError("Unknown appliance!")
|
||||||
|
@ -78,31 +156,41 @@ def test_discovery_request(hass):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_api_entity_not_exists(hass):
|
def test_api_entity_not_exists(hass):
|
||||||
"""Test api turn on process without entity."""
|
"""Test api turn on process without entity."""
|
||||||
msg_switch = smart_home.api_message(
|
request = get_new_request('Alexa.PowerController', 'TurnOn', 'switch#test')
|
||||||
'TurnOnRequest', 'Alexa.ConnectedHome.Control', {
|
|
||||||
'appliance': {
|
|
||||||
'applianceId': 'switch#test'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
call_switch = async_mock_service(hass, 'switch', 'turn_on')
|
call_switch = async_mock_service(hass, 'switch', 'turn_on')
|
||||||
|
|
||||||
resp = yield from smart_home.async_api_turn_on(hass, msg_switch)
|
msg = yield from smart_home.async_handle_message(hass, request)
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
assert len(call_switch) == 0
|
assert len(call_switch) == 0
|
||||||
assert resp['header']['name'] == 'DriverInternalError'
|
assert msg['header']['name'] == 'ErrorResponse'
|
||||||
assert resp['header']['namespace'] == 'Alexa.ConnectedHome.Control'
|
assert msg['header']['namespace'] == 'Alexa'
|
||||||
|
assert msg['payload']['type'] == 'NO_SUCH_ENDPOINT'
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_api_function_not_implemented(hass):
|
||||||
|
"""Test api call that is not implemented to us."""
|
||||||
|
request = get_new_request('Alexa.HAHAAH', 'Sweet')
|
||||||
|
msg = yield from smart_home.async_handle_message(hass, request)
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
|
assert msg['header']['name'] == 'ErrorResponse'
|
||||||
|
assert msg['header']['namespace'] == 'Alexa'
|
||||||
|
assert msg['payload']['type'] == 'INTERNAL_ERROR'
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@pytest.mark.parametrize("domain", ['light', 'switch'])
|
@pytest.mark.parametrize("domain", ['light', 'switch'])
|
||||||
def test_api_turn_on(hass, domain):
|
def test_api_turn_on(hass, domain):
|
||||||
"""Test api turn on process."""
|
"""Test api turn on process."""
|
||||||
msg = smart_home.api_message(
|
request = get_new_request(
|
||||||
'TurnOnRequest', 'Alexa.ConnectedHome.Control', {
|
'Alexa.PowerController', 'TurnOn', '{}#test'.format(domain))
|
||||||
'appliance': {
|
|
||||||
'applianceId': '{}#test'.format(domain)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
# settup test devices
|
# settup test devices
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -112,22 +200,22 @@ def test_api_turn_on(hass, domain):
|
||||||
|
|
||||||
call = async_mock_service(hass, domain, 'turn_on')
|
call = async_mock_service(hass, domain, 'turn_on')
|
||||||
|
|
||||||
resp = yield from smart_home.async_api_turn_on(hass, msg)
|
msg = yield from smart_home.async_handle_message(hass, request)
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
assert len(call) == 1
|
assert len(call) == 1
|
||||||
assert call[0].data['entity_id'] == '{}.test'.format(domain)
|
assert call[0].data['entity_id'] == '{}.test'.format(domain)
|
||||||
assert resp['header']['name'] == 'TurnOnConfirmation'
|
assert msg['header']['name'] == 'Response'
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@pytest.mark.parametrize("domain", ['light', 'switch'])
|
@pytest.mark.parametrize("domain", ['light', 'switch'])
|
||||||
def test_api_turn_off(hass, domain):
|
def test_api_turn_off(hass, domain):
|
||||||
"""Test api turn on process."""
|
"""Test api turn on process."""
|
||||||
msg = smart_home.api_message(
|
request = get_new_request(
|
||||||
'TurnOffRequest', 'Alexa.ConnectedHome.Control', {
|
'Alexa.PowerController', 'TurnOff', '{}#test'.format(domain))
|
||||||
'appliance': {
|
|
||||||
'applianceId': '{}#test'.format(domain)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
# settup test devices
|
# settup test devices
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -137,24 +225,24 @@ def test_api_turn_off(hass, domain):
|
||||||
|
|
||||||
call = async_mock_service(hass, domain, 'turn_off')
|
call = async_mock_service(hass, domain, 'turn_off')
|
||||||
|
|
||||||
resp = yield from smart_home.async_api_turn_off(hass, msg)
|
msg = yield from smart_home.async_handle_message(hass, request)
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
assert len(call) == 1
|
assert len(call) == 1
|
||||||
assert call[0].data['entity_id'] == '{}.test'.format(domain)
|
assert call[0].data['entity_id'] == '{}.test'.format(domain)
|
||||||
assert resp['header']['name'] == 'TurnOffConfirmation'
|
assert msg['header']['name'] == 'Response'
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_api_set_percentage_light(hass):
|
def test_api_set_brightness(hass):
|
||||||
"""Test api set brightness process."""
|
"""Test api set brightness process."""
|
||||||
msg_light = smart_home.api_message(
|
request = get_new_request(
|
||||||
'SetPercentageRequest', 'Alexa.ConnectedHome.Control', {
|
'Alexa.BrightnessController', 'SetBrightness', 'light#test')
|
||||||
'appliance': {
|
|
||||||
'applianceId': 'light#test'
|
# add payload
|
||||||
},
|
request['directive']['payload']['brightness'] = '50'
|
||||||
'percentageState': {
|
|
||||||
'value': '50'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
# settup test devices
|
# settup test devices
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -162,8 +250,12 @@ def test_api_set_percentage_light(hass):
|
||||||
|
|
||||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||||
|
|
||||||
resp = yield from smart_home.async_api_set_percentage(hass, msg_light)
|
msg = yield from smart_home.async_handle_message(hass, request)
|
||||||
|
|
||||||
|
assert 'event' in msg
|
||||||
|
msg = msg['event']
|
||||||
|
|
||||||
assert len(call_light) == 1
|
assert len(call_light) == 1
|
||||||
assert call_light[0].data['entity_id'] == 'light.test'
|
assert call_light[0].data['entity_id'] == 'light.test'
|
||||||
assert call_light[0].data['brightness'] == '50'
|
assert call_light[0].data['brightness'] == '50'
|
||||||
assert resp['header']['name'] == 'SetPercentageConfirmation'
|
assert msg['header']['name'] == 'Response'
|
||||||
|
|
Loading…
Add table
Reference in a new issue