Implement entity and domain exclude/include for Alexa (#10647)
* Implement entity and domain exclude/include for Alexa * Switch to using generate_filter * Use proper domain for turn on/off calls except for groups where we must use the generic homeassistant.turn_on/off * travis fixes * Untangle * Lintpull/10644/merge
parent
64a393b377
commit
1317297191
|
@ -1,5 +1,6 @@
|
|||
"""Support for alexa Smart Home Skill API."""
|
||||
import asyncio
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import math
|
||||
from uuid import uuid4
|
||||
|
@ -72,8 +73,11 @@ MAPPING_COMPONENT = {
|
|||
}
|
||||
|
||||
|
||||
Config = namedtuple('AlexaConfig', 'filter')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_handle_message(hass, message):
|
||||
def async_handle_message(hass, config, message):
|
||||
"""Handle incoming API messages."""
|
||||
assert message[API_DIRECTIVE][API_HEADER]['payloadVersion'] == '3'
|
||||
|
||||
|
@ -89,7 +93,7 @@ def async_handle_message(hass, message):
|
|||
"Unsupported API request %s/%s", namespace, name)
|
||||
return api_error(message)
|
||||
|
||||
return (yield from funct_ref(hass, message))
|
||||
return (yield from funct_ref(hass, config, message))
|
||||
|
||||
|
||||
def api_message(request, name='Response', namespace='Alexa', payload=None):
|
||||
|
@ -138,7 +142,7 @@ def api_error(request, error_type='INTERNAL_ERROR', error_message=""):
|
|||
|
||||
@HANDLERS.register(('Alexa.Discovery', 'Discover'))
|
||||
@asyncio.coroutine
|
||||
def async_api_discovery(hass, request):
|
||||
def async_api_discovery(hass, config, request):
|
||||
"""Create a API formatted discovery response.
|
||||
|
||||
Async friendly.
|
||||
|
@ -146,7 +150,14 @@ def async_api_discovery(hass, request):
|
|||
discovery_endpoints = []
|
||||
|
||||
for entity in hass.states.async_all():
|
||||
if not config.filter(entity.entity_id):
|
||||
_LOGGER.debug("Not exposing %s because filtered by config",
|
||||
entity.entity_id)
|
||||
continue
|
||||
|
||||
if entity.attributes.get(ATTR_ALEXA_HIDDEN, False):
|
||||
_LOGGER.debug("Not exposing %s because alexa_hidden is true",
|
||||
entity.entity_id)
|
||||
continue
|
||||
|
||||
class_data = MAPPING_COMPONENT.get(entity.domain)
|
||||
|
@ -207,7 +218,7 @@ def async_api_discovery(hass, request):
|
|||
def extract_entity(funct):
|
||||
"""Decorator for extract entity object from request."""
|
||||
@asyncio.coroutine
|
||||
def async_api_entity_wrapper(hass, request):
|
||||
def async_api_entity_wrapper(hass, config, request):
|
||||
"""Process a turn on request."""
|
||||
entity_id = request[API_ENDPOINT]['endpointId'].replace('#', '.')
|
||||
|
||||
|
@ -218,7 +229,7 @@ def extract_entity(funct):
|
|||
request[API_HEADER]['name'], entity_id)
|
||||
return api_error(request, error_type='NO_SUCH_ENDPOINT')
|
||||
|
||||
return (yield from funct(hass, request, entity))
|
||||
return (yield from funct(hass, config, request, entity))
|
||||
|
||||
return async_api_entity_wrapper
|
||||
|
||||
|
@ -226,9 +237,13 @@ def extract_entity(funct):
|
|||
@HANDLERS.register(('Alexa.PowerController', 'TurnOn'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_turn_on(hass, request, entity):
|
||||
def async_api_turn_on(hass, config, request, entity):
|
||||
"""Process a turn on request."""
|
||||
yield from hass.services.async_call(ha.DOMAIN, SERVICE_TURN_ON, {
|
||||
domain = entity.domain
|
||||
if entity.domain == group.DOMAIN:
|
||||
domain = ha.DOMAIN
|
||||
|
||||
yield from hass.services.async_call(domain, SERVICE_TURN_ON, {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
}, blocking=True)
|
||||
|
||||
|
@ -238,9 +253,13 @@ def async_api_turn_on(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PowerController', 'TurnOff'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_turn_off(hass, request, entity):
|
||||
def async_api_turn_off(hass, config, request, entity):
|
||||
"""Process a turn off request."""
|
||||
yield from hass.services.async_call(ha.DOMAIN, SERVICE_TURN_OFF, {
|
||||
domain = entity.domain
|
||||
if entity.domain == group.DOMAIN:
|
||||
domain = ha.DOMAIN
|
||||
|
||||
yield from hass.services.async_call(domain, SERVICE_TURN_OFF, {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
}, blocking=True)
|
||||
|
||||
|
@ -250,7 +269,7 @@ def async_api_turn_off(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.BrightnessController', 'SetBrightness'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_set_brightness(hass, request, entity):
|
||||
def async_api_set_brightness(hass, config, request, entity):
|
||||
"""Process a set brightness request."""
|
||||
brightness = int(request[API_PAYLOAD]['brightness'])
|
||||
|
||||
|
@ -265,7 +284,7 @@ def async_api_set_brightness(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.BrightnessController', 'AdjustBrightness'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_adjust_brightness(hass, request, entity):
|
||||
def async_api_adjust_brightness(hass, config, request, entity):
|
||||
"""Process a adjust brightness request."""
|
||||
brightness_delta = int(request[API_PAYLOAD]['brightnessDelta'])
|
||||
|
||||
|
@ -289,7 +308,7 @@ def async_api_adjust_brightness(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.ColorController', 'SetColor'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_set_color(hass, request, entity):
|
||||
def async_api_set_color(hass, config, request, entity):
|
||||
"""Process a set color request."""
|
||||
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||
rgb = color_util.color_hsb_to_RGB(
|
||||
|
@ -317,7 +336,7 @@ def async_api_set_color(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.ColorTemperatureController', 'SetColorTemperature'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_set_color_temperature(hass, request, entity):
|
||||
def async_api_set_color_temperature(hass, config, request, entity):
|
||||
"""Process a set color temperature request."""
|
||||
kelvin = int(request[API_PAYLOAD]['colorTemperatureInKelvin'])
|
||||
|
||||
|
@ -333,7 +352,7 @@ def async_api_set_color_temperature(hass, request, entity):
|
|||
('Alexa.ColorTemperatureController', 'DecreaseColorTemperature'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_decrease_color_temp(hass, request, entity):
|
||||
def async_api_decrease_color_temp(hass, config, request, entity):
|
||||
"""Process a decrease color temperature request."""
|
||||
current = int(entity.attributes.get(light.ATTR_COLOR_TEMP))
|
||||
max_mireds = int(entity.attributes.get(light.ATTR_MAX_MIREDS))
|
||||
|
@ -351,7 +370,7 @@ def async_api_decrease_color_temp(hass, request, entity):
|
|||
('Alexa.ColorTemperatureController', 'IncreaseColorTemperature'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_increase_color_temp(hass, request, entity):
|
||||
def async_api_increase_color_temp(hass, config, request, entity):
|
||||
"""Process a increase color temperature request."""
|
||||
current = int(entity.attributes.get(light.ATTR_COLOR_TEMP))
|
||||
min_mireds = int(entity.attributes.get(light.ATTR_MIN_MIREDS))
|
||||
|
@ -368,7 +387,7 @@ def async_api_increase_color_temp(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.SceneController', 'Activate'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_activate(hass, request, entity):
|
||||
def async_api_activate(hass, config, request, entity):
|
||||
"""Process a activate request."""
|
||||
yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -380,7 +399,7 @@ def async_api_activate(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PercentageController', 'SetPercentage'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_set_percentage(hass, request, entity):
|
||||
def async_api_set_percentage(hass, config, request, entity):
|
||||
"""Process a set percentage request."""
|
||||
percentage = int(request[API_PAYLOAD]['percentage'])
|
||||
service = None
|
||||
|
@ -411,7 +430,7 @@ def async_api_set_percentage(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PercentageController', 'AdjustPercentage'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_adjust_percentage(hass, request, entity):
|
||||
def async_api_adjust_percentage(hass, config, request, entity):
|
||||
"""Process a adjust percentage request."""
|
||||
percentage_delta = int(request[API_PAYLOAD]['percentageDelta'])
|
||||
service = None
|
||||
|
@ -459,7 +478,7 @@ def async_api_adjust_percentage(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.LockController', 'Lock'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_lock(hass, request, entity):
|
||||
def async_api_lock(hass, config, request, entity):
|
||||
"""Process a lock request."""
|
||||
yield from hass.services.async_call(entity.domain, SERVICE_LOCK, {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -472,7 +491,7 @@ def async_api_lock(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.LockController', 'Unlock'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_unlock(hass, request, entity):
|
||||
def async_api_unlock(hass, config, request, entity):
|
||||
"""Process a unlock request."""
|
||||
yield from hass.services.async_call(entity.domain, SERVICE_UNLOCK, {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -484,7 +503,7 @@ def async_api_unlock(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.Speaker', 'SetVolume'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_set_volume(hass, request, entity):
|
||||
def async_api_set_volume(hass, config, request, entity):
|
||||
"""Process a set volume request."""
|
||||
volume = round(float(request[API_PAYLOAD]['volume'] / 100), 2)
|
||||
|
||||
|
@ -502,7 +521,7 @@ def async_api_set_volume(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.Speaker', 'AdjustVolume'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_adjust_volume(hass, request, entity):
|
||||
def async_api_adjust_volume(hass, config, request, entity):
|
||||
"""Process a adjust volume request."""
|
||||
volume_delta = int(request[API_PAYLOAD]['volume'])
|
||||
|
||||
|
@ -531,7 +550,7 @@ def async_api_adjust_volume(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.Speaker', 'SetMute'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_set_mute(hass, request, entity):
|
||||
def async_api_set_mute(hass, config, request, entity):
|
||||
"""Process a set mute request."""
|
||||
mute = bool(request[API_PAYLOAD]['mute'])
|
||||
|
||||
|
@ -550,7 +569,7 @@ def async_api_set_mute(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PlaybackController', 'Play'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_play(hass, request, entity):
|
||||
def async_api_play(hass, config, request, entity):
|
||||
"""Process a play request."""
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -565,7 +584,7 @@ def async_api_play(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PlaybackController', 'Pause'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_pause(hass, request, entity):
|
||||
def async_api_pause(hass, config, request, entity):
|
||||
"""Process a pause request."""
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -580,7 +599,7 @@ def async_api_pause(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PlaybackController', 'Stop'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_stop(hass, request, entity):
|
||||
def async_api_stop(hass, config, request, entity):
|
||||
"""Process a stop request."""
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -595,7 +614,7 @@ def async_api_stop(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PlaybackController', 'Next'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_next(hass, request, entity):
|
||||
def async_api_next(hass, config, request, entity):
|
||||
"""Process a next request."""
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
@ -611,7 +630,7 @@ def async_api_next(hass, request, entity):
|
|||
@HANDLERS.register(('Alexa.PlaybackController', 'Previous'))
|
||||
@extract_entity
|
||||
@asyncio.coroutine
|
||||
def async_api_previous(hass, request, entity):
|
||||
def async_api_previous(hass, config, request, entity):
|
||||
"""Process a previous request."""
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id
|
||||
|
|
|
@ -9,7 +9,9 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.const import (
|
||||
EVENT_HOMEASSISTANT_START, CONF_REGION, CONF_MODE)
|
||||
from homeassistant.helpers import entityfilter
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.components.alexa import smart_home
|
||||
|
||||
from . import http_api, iot
|
||||
from .const import CONFIG_DIR, DOMAIN, SERVERS
|
||||
|
@ -18,6 +20,8 @@ REQUIREMENTS = ['warrant==0.5.0']
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_ALEXA = 'alexa'
|
||||
CONF_ALEXA_FILTER = 'filter'
|
||||
CONF_COGNITO_CLIENT_ID = 'cognito_client_id'
|
||||
CONF_RELAYER = 'relayer'
|
||||
CONF_USER_POOL_ID = 'user_pool_id'
|
||||
|
@ -26,6 +30,13 @@ MODE_DEV = 'development'
|
|||
DEFAULT_MODE = MODE_DEV
|
||||
DEPENDENCIES = ['http']
|
||||
|
||||
ALEXA_SCHEMA = vol.Schema({
|
||||
vol.Optional(
|
||||
CONF_ALEXA_FILTER,
|
||||
default=lambda: entityfilter.generate_filter([], [], [], [])
|
||||
): entityfilter.FILTER_SCHEMA,
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Optional(CONF_MODE, default=DEFAULT_MODE):
|
||||
|
@ -35,6 +46,7 @@ CONFIG_SCHEMA = vol.Schema({
|
|||
vol.Required(CONF_USER_POOL_ID): str,
|
||||
vol.Required(CONF_REGION): str,
|
||||
vol.Required(CONF_RELAYER): str,
|
||||
vol.Optional(CONF_ALEXA): ALEXA_SCHEMA
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
@ -47,6 +59,10 @@ def async_setup(hass, config):
|
|||
else:
|
||||
kwargs = {CONF_MODE: DEFAULT_MODE}
|
||||
|
||||
if CONF_ALEXA not in kwargs:
|
||||
kwargs[CONF_ALEXA] = ALEXA_SCHEMA({})
|
||||
|
||||
kwargs[CONF_ALEXA] = smart_home.Config(**kwargs[CONF_ALEXA])
|
||||
cloud = hass.data[DOMAIN] = Cloud(hass, **kwargs)
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -64,10 +80,11 @@ class Cloud:
|
|||
"""Store the configuration of the cloud connection."""
|
||||
|
||||
def __init__(self, hass, mode, cognito_client_id=None, user_pool_id=None,
|
||||
region=None, relayer=None):
|
||||
region=None, relayer=None, alexa=None):
|
||||
"""Create an instance of Cloud."""
|
||||
self.hass = hass
|
||||
self.mode = mode
|
||||
self.alexa_config = alexa
|
||||
self.id_token = None
|
||||
self.access_token = None
|
||||
self.refresh_token = None
|
||||
|
|
|
@ -206,7 +206,9 @@ def async_handle_message(hass, cloud, handler_name, payload):
|
|||
@asyncio.coroutine
|
||||
def async_handle_alexa(hass, cloud, payload):
|
||||
"""Handle an incoming IoT message for Alexa."""
|
||||
return (yield from smart_home.async_handle_message(hass, payload))
|
||||
return (yield from smart_home.async_handle_message(hass,
|
||||
cloud.alexa_config,
|
||||
payload))
|
||||
|
||||
|
||||
@HANDLERS.register('cloud')
|
||||
|
|
|
@ -25,7 +25,17 @@ DEPENDENCIES = ['mqtt']
|
|||
DOMAIN = 'mqtt_statestream'
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: cv.FILTER_SCHEMA.extend({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Optional(CONF_EXCLUDE, default={}): vol.Schema({
|
||||
vol.Optional(CONF_ENTITIES, default=[]): cv.entity_ids,
|
||||
vol.Optional(CONF_DOMAINS, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string])
|
||||
}),
|
||||
vol.Optional(CONF_INCLUDE, default={}): vol.Schema({
|
||||
vol.Optional(CONF_ENTITIES, default=[]): cv.entity_ids,
|
||||
vol.Optional(CONF_DOMAINS, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string])
|
||||
}),
|
||||
vol.Required(CONF_BASE_TOPIC): valid_publish_topic,
|
||||
vol.Optional(CONF_PUBLISH_ATTRIBUTES, default=False): cv.boolean,
|
||||
vol.Optional(CONF_PUBLISH_TIMESTAMPS, default=False): cv.boolean
|
||||
|
|
|
@ -12,8 +12,7 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.loader import get_platform
|
||||
from homeassistant.const import (
|
||||
CONF_DOMAINS, CONF_ENTITIES, CONF_EXCLUDE, CONF_INCLUDE, CONF_PLATFORM,
|
||||
CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS,
|
||||
CONF_CONDITION, CONF_BELOW, CONF_ABOVE, CONF_TIMEOUT, SUN_EVENT_SUNSET,
|
||||
SUN_EVENT_SUNRISE, CONF_UNIT_SYSTEM_IMPERIAL, CONF_UNIT_SYSTEM_METRIC)
|
||||
|
@ -563,16 +562,3 @@ SCRIPT_SCHEMA = vol.All(
|
|||
[vol.Any(SERVICE_SCHEMA, _SCRIPT_DELAY_SCHEMA,
|
||||
_SCRIPT_WAIT_TEMPLATE_SCHEMA, EVENT_SCHEMA, CONDITION_SCHEMA)],
|
||||
)
|
||||
|
||||
FILTER_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_EXCLUDE, default={}): vol.Schema({
|
||||
vol.Optional(CONF_ENTITIES, default=[]): entity_ids,
|
||||
vol.Optional(CONF_DOMAINS, default=[]):
|
||||
vol.All(ensure_list, [string])
|
||||
}),
|
||||
vol.Optional(CONF_INCLUDE, default={}): vol.Schema({
|
||||
vol.Optional(CONF_ENTITIES, default=[]): entity_ids,
|
||||
vol.Optional(CONF_DOMAINS, default=[]):
|
||||
vol.All(ensure_list, [string])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,30 @@
|
|||
"""Helper class to implement include/exclude of entities and domains."""
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import split_entity_id
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
CONF_INCLUDE_DOMAINS = 'include_domains'
|
||||
CONF_INCLUDE_ENTITIES = 'include_entities'
|
||||
CONF_EXCLUDE_DOMAINS = 'exclude_domains'
|
||||
CONF_EXCLUDE_ENTITIES = 'exclude_entities'
|
||||
|
||||
FILTER_SCHEMA = vol.All(
|
||||
vol.Schema({
|
||||
vol.Optional(CONF_EXCLUDE_DOMAINS, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_EXCLUDE_ENTITIES, default=[]): cv.entity_ids,
|
||||
vol.Optional(CONF_INCLUDE_DOMAINS, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_INCLUDE_ENTITIES, default=[]): cv.entity_ids,
|
||||
}),
|
||||
lambda config: generate_filter(
|
||||
config[CONF_INCLUDE_DOMAINS],
|
||||
config[CONF_INCLUDE_ENTITIES],
|
||||
config[CONF_EXCLUDE_DOMAINS],
|
||||
config[CONF_EXCLUDE_ENTITIES],
|
||||
))
|
||||
|
||||
|
||||
def generate_filter(include_domains, include_entities,
|
||||
|
|
|
@ -5,9 +5,12 @@ from uuid import uuid4
|
|||
import pytest
|
||||
|
||||
from homeassistant.components.alexa import smart_home
|
||||
from homeassistant.helpers import entityfilter
|
||||
|
||||
from tests.common import async_mock_service
|
||||
|
||||
DEFAULT_CONFIG = smart_home.Config(filter=lambda entity_id: True)
|
||||
|
||||
|
||||
def get_new_request(namespace, name, endpoint=None):
|
||||
"""Generate a new API message."""
|
||||
|
@ -91,7 +94,7 @@ def test_wrong_version(hass):
|
|||
msg['directive']['header']['payloadVersion'] = '2'
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
yield from smart_home.async_handle_message(hass, msg)
|
||||
yield from smart_home.async_handle_message(hass, DEFAULT_CONFIG, msg)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -157,7 +160,8 @@ def test_discovery_request(hass):
|
|||
'position': 85
|
||||
})
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -319,6 +323,67 @@ def test_discovery_request(hass):
|
|||
raise AssertionError("Unknown appliance!")
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_exclude_filters(hass):
|
||||
"""Test exclusion filters."""
|
||||
request = get_new_request('Alexa.Discovery', 'Discover')
|
||||
|
||||
# setup test devices
|
||||
hass.states.async_set(
|
||||
'switch.test', 'on', {'friendly_name': "Test switch"})
|
||||
|
||||
hass.states.async_set(
|
||||
'script.deny', 'off', {'friendly_name': "Blocked script"})
|
||||
|
||||
hass.states.async_set(
|
||||
'cover.deny', 'off', {'friendly_name': "Blocked cover"})
|
||||
|
||||
config = smart_home.Config(filter=entityfilter.generate_filter(
|
||||
include_domains=[],
|
||||
include_entities=[],
|
||||
exclude_domains=['script'],
|
||||
exclude_entities=['cover.deny'],
|
||||
))
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, config, request)
|
||||
|
||||
msg = msg['event']
|
||||
|
||||
assert len(msg['payload']['endpoints']) == 1
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_include_filters(hass):
|
||||
"""Test inclusion filters."""
|
||||
request = get_new_request('Alexa.Discovery', 'Discover')
|
||||
|
||||
# setup test devices
|
||||
hass.states.async_set(
|
||||
'switch.deny', 'on', {'friendly_name': "Blocked switch"})
|
||||
|
||||
hass.states.async_set(
|
||||
'script.deny', 'off', {'friendly_name': "Blocked script"})
|
||||
|
||||
hass.states.async_set(
|
||||
'automation.allow', 'off', {'friendly_name': "Allowed automation"})
|
||||
|
||||
hass.states.async_set(
|
||||
'group.allow', 'off', {'friendly_name': "Allowed group"})
|
||||
|
||||
config = smart_home.Config(filter=entityfilter.generate_filter(
|
||||
include_domains=['automation', 'group'],
|
||||
include_entities=['script.deny'],
|
||||
exclude_domains=[],
|
||||
exclude_entities=[],
|
||||
))
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, config, request)
|
||||
|
||||
msg = msg['event']
|
||||
|
||||
assert len(msg['payload']['endpoints']) == 3
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_api_entity_not_exists(hass):
|
||||
"""Test api turn on process without entity."""
|
||||
|
@ -326,7 +391,8 @@ def test_api_entity_not_exists(hass):
|
|||
|
||||
call_switch = async_mock_service(hass, 'switch', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -341,7 +407,8 @@ def test_api_entity_not_exists(hass):
|
|||
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)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -366,9 +433,15 @@ def test_api_turn_on(hass, domain):
|
|||
'friendly_name': "Test {}".format(domain)
|
||||
})
|
||||
|
||||
call = async_mock_service(hass, 'homeassistant', 'turn_on')
|
||||
call_domain = domain
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
if domain == 'group':
|
||||
call_domain = 'homeassistant'
|
||||
|
||||
call = async_mock_service(hass, call_domain, 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -393,9 +466,15 @@ def test_api_turn_off(hass, domain):
|
|||
'friendly_name': "Test {}".format(domain)
|
||||
})
|
||||
|
||||
call = async_mock_service(hass, 'homeassistant', 'turn_off')
|
||||
call_domain = domain
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
if domain == 'group':
|
||||
call_domain = 'homeassistant'
|
||||
|
||||
call = async_mock_service(hass, call_domain, 'turn_off')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -420,7 +499,8 @@ def test_api_set_brightness(hass):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -450,7 +530,8 @@ def test_api_adjust_brightness(hass, result, adjust):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -483,7 +564,8 @@ def test_api_set_color_rgb(hass):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -516,7 +598,8 @@ def test_api_set_color_xy(hass):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -544,7 +627,8 @@ def test_api_set_color_temperature(hass):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -572,7 +656,8 @@ def test_api_decrease_color_temp(hass, result, initial):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -600,7 +685,8 @@ def test_api_increase_color_temp(hass, result, initial):
|
|||
|
||||
call_light = async_mock_service(hass, 'light', 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -626,7 +712,8 @@ def test_api_activate(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'turn_on')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -651,7 +738,8 @@ def test_api_set_percentage_fan(hass):
|
|||
|
||||
call_fan = async_mock_service(hass, 'fan', 'set_speed')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -679,7 +767,8 @@ def test_api_set_percentage_cover(hass):
|
|||
|
||||
call_cover = async_mock_service(hass, 'cover', 'set_cover_position')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -709,7 +798,8 @@ def test_api_adjust_percentage_fan(hass, result, adjust):
|
|||
|
||||
call_fan = async_mock_service(hass, 'fan', 'set_speed')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -740,7 +830,8 @@ def test_api_adjust_percentage_cover(hass, result, adjust):
|
|||
|
||||
call_cover = async_mock_service(hass, 'cover', 'set_cover_position')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -766,7 +857,8 @@ def test_api_lock(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'lock')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -791,7 +883,8 @@ def test_api_play(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'media_play')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -816,7 +909,8 @@ def test_api_pause(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'media_pause')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -841,7 +935,8 @@ def test_api_stop(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'media_stop')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -866,7 +961,8 @@ def test_api_next(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'media_next_track')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -891,7 +987,8 @@ def test_api_previous(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'media_previous_track')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -918,7 +1015,8 @@ def test_api_set_volume(hass):
|
|||
|
||||
call_media_player = async_mock_service(hass, 'media_player', 'volume_set')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -948,7 +1046,8 @@ def test_api_adjust_volume(hass, result, adjust):
|
|||
|
||||
call_media_player = async_mock_service(hass, 'media_player', 'volume_set')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
@ -976,7 +1075,8 @@ def test_api_mute(hass, domain):
|
|||
|
||||
call = async_mock_service(hass, domain, 'volume_mute')
|
||||
|
||||
msg = yield from smart_home.async_handle_message(hass, request)
|
||||
msg = yield from smart_home.async_handle_message(
|
||||
hass, DEFAULT_CONFIG, request)
|
||||
|
||||
assert 'event' in msg
|
||||
msg = msg['event']
|
||||
|
|
Loading…
Reference in New Issue