|
|
|
@ -1,9 +1,9 @@
|
|
|
|
|
"""The tests for the emulated Hue component."""
|
|
|
|
|
import asyncio
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
import unittest
|
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
import requests
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from homeassistant import bootstrap, const, core
|
|
|
|
|
import homeassistant.components as core_components
|
|
|
|
@ -12,10 +12,12 @@ from homeassistant.components import (
|
|
|
|
|
)
|
|
|
|
|
from homeassistant.const import STATE_ON, STATE_OFF
|
|
|
|
|
from homeassistant.components.emulated_hue.hue_api import (
|
|
|
|
|
HUE_API_STATE_ON, HUE_API_STATE_BRI)
|
|
|
|
|
from homeassistant.util.async import run_coroutine_threadsafe
|
|
|
|
|
HUE_API_STATE_ON, HUE_API_STATE_BRI, HueUsernameView,
|
|
|
|
|
HueAllLightsStateView, HueOneLightStateView, HueOneLightChangeView)
|
|
|
|
|
from homeassistant.components.emulated_hue import Config
|
|
|
|
|
|
|
|
|
|
from tests.common import get_test_instance_port, get_test_home_assistant
|
|
|
|
|
from tests.common import (
|
|
|
|
|
get_test_instance_port, mock_http_component_app)
|
|
|
|
|
|
|
|
|
|
HTTP_SERVER_PORT = get_test_instance_port()
|
|
|
|
|
BRIDGE_SERVER_PORT = get_test_instance_port()
|
|
|
|
@ -24,41 +26,38 @@ BRIDGE_URL_BASE = 'http://127.0.0.1:{}'.format(BRIDGE_SERVER_PORT) + '{}'
|
|
|
|
|
JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestEmulatedHueExposedByDefault(unittest.TestCase):
|
|
|
|
|
"""Test class for emulated hue component."""
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def hass_hue(loop, hass):
|
|
|
|
|
"""Setup a hass instance for these tests."""
|
|
|
|
|
# We need to do this to get access to homeassistant/turn_(on,off)
|
|
|
|
|
loop.run_until_complete(
|
|
|
|
|
core_components.async_setup(hass, {core.DOMAIN: {}}))
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def setUpClass(cls):
|
|
|
|
|
"""Setup the class."""
|
|
|
|
|
cls.hass = hass = get_test_home_assistant()
|
|
|
|
|
loop.run_until_complete(bootstrap.async_setup_component(
|
|
|
|
|
hass, http.DOMAIN,
|
|
|
|
|
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}}))
|
|
|
|
|
|
|
|
|
|
# We need to do this to get access to homeassistant/turn_(on,off)
|
|
|
|
|
run_coroutine_threadsafe(
|
|
|
|
|
core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop
|
|
|
|
|
).result()
|
|
|
|
|
|
|
|
|
|
bootstrap.setup_component(
|
|
|
|
|
hass, http.DOMAIN,
|
|
|
|
|
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}})
|
|
|
|
|
|
|
|
|
|
with patch('homeassistant.components'
|
|
|
|
|
'.emulated_hue.UPNPResponderThread'):
|
|
|
|
|
bootstrap.setup_component(hass, emulated_hue.DOMAIN, {
|
|
|
|
|
with patch('homeassistant.components'
|
|
|
|
|
'.emulated_hue.UPNPResponderThread'):
|
|
|
|
|
loop.run_until_complete(
|
|
|
|
|
bootstrap.async_setup_component(hass, emulated_hue.DOMAIN, {
|
|
|
|
|
emulated_hue.DOMAIN: {
|
|
|
|
|
emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT,
|
|
|
|
|
emulated_hue.CONF_EXPOSE_BY_DEFAULT: True
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
bootstrap.setup_component(cls.hass, light.DOMAIN, {
|
|
|
|
|
loop.run_until_complete(
|
|
|
|
|
bootstrap.async_setup_component(hass, light.DOMAIN, {
|
|
|
|
|
'light': [
|
|
|
|
|
{
|
|
|
|
|
'platform': 'demo',
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
bootstrap.setup_component(cls.hass, script.DOMAIN, {
|
|
|
|
|
loop.run_until_complete(
|
|
|
|
|
bootstrap.async_setup_component(hass, script.DOMAIN, {
|
|
|
|
|
'script': {
|
|
|
|
|
'set_kitchen_light': {
|
|
|
|
|
'sequence': [
|
|
|
|
@ -73,338 +72,354 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase):
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
bootstrap.setup_component(cls.hass, media_player.DOMAIN, {
|
|
|
|
|
loop.run_until_complete(
|
|
|
|
|
bootstrap.async_setup_component(hass, media_player.DOMAIN, {
|
|
|
|
|
'media_player': [
|
|
|
|
|
{
|
|
|
|
|
'platform': 'demo',
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
cls.hass.start()
|
|
|
|
|
# Kitchen light is explicitly excluded from being exposed
|
|
|
|
|
kitchen_light_entity = hass.states.get('light.kitchen_lights')
|
|
|
|
|
attrs = dict(kitchen_light_entity.attributes)
|
|
|
|
|
attrs[emulated_hue.ATTR_EMULATED_HUE] = False
|
|
|
|
|
hass.states.async_set(
|
|
|
|
|
kitchen_light_entity.entity_id, kitchen_light_entity.state,
|
|
|
|
|
attributes=attrs)
|
|
|
|
|
|
|
|
|
|
# Kitchen light is explicitly excluded from being exposed
|
|
|
|
|
kitchen_light_entity = cls.hass.states.get('light.kitchen_lights')
|
|
|
|
|
attrs = dict(kitchen_light_entity.attributes)
|
|
|
|
|
attrs[emulated_hue.ATTR_EMULATED_HUE] = False
|
|
|
|
|
cls.hass.states.set(
|
|
|
|
|
kitchen_light_entity.entity_id, kitchen_light_entity.state,
|
|
|
|
|
attributes=attrs)
|
|
|
|
|
# Expose the script
|
|
|
|
|
script_entity = hass.states.get('script.set_kitchen_light')
|
|
|
|
|
attrs = dict(script_entity.attributes)
|
|
|
|
|
attrs[emulated_hue.ATTR_EMULATED_HUE] = True
|
|
|
|
|
hass.states.async_set(
|
|
|
|
|
script_entity.entity_id, script_entity.state, attributes=attrs
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Expose the script
|
|
|
|
|
script_entity = cls.hass.states.get('script.set_kitchen_light')
|
|
|
|
|
attrs = dict(script_entity.attributes)
|
|
|
|
|
attrs[emulated_hue.ATTR_EMULATED_HUE] = True
|
|
|
|
|
cls.hass.states.set(
|
|
|
|
|
script_entity.entity_id, script_entity.state, attributes=attrs
|
|
|
|
|
)
|
|
|
|
|
return hass
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def tearDownClass(cls):
|
|
|
|
|
"""Stop the class."""
|
|
|
|
|
cls.hass.stop()
|
|
|
|
|
|
|
|
|
|
def test_discover_lights(self):
|
|
|
|
|
"""Test the discovery of lights."""
|
|
|
|
|
result = requests.get(
|
|
|
|
|
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5)
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def hue_client(loop, hass_hue, test_client):
|
|
|
|
|
"""Create web client for emulated hue api."""
|
|
|
|
|
web_app = mock_http_component_app(hass_hue)
|
|
|
|
|
config = Config({'type': 'alexa'})
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
self.assertTrue('application/json' in result.headers['content-type'])
|
|
|
|
|
HueUsernameView().register(web_app.router)
|
|
|
|
|
HueAllLightsStateView(config).register(web_app.router)
|
|
|
|
|
HueOneLightStateView(config).register(web_app.router)
|
|
|
|
|
HueOneLightChangeView(config).register(web_app.router)
|
|
|
|
|
|
|
|
|
|
result_json = result.json()
|
|
|
|
|
return loop.run_until_complete(test_client(web_app))
|
|
|
|
|
|
|
|
|
|
# Make sure the lights we added to the config are there
|
|
|
|
|
self.assertTrue('light.ceiling_lights' in result_json)
|
|
|
|
|
self.assertTrue('light.bed_light' in result_json)
|
|
|
|
|
self.assertTrue('script.set_kitchen_light' in result_json)
|
|
|
|
|
self.assertTrue('light.kitchen_lights' not in result_json)
|
|
|
|
|
self.assertTrue('media_player.living_room' in result_json)
|
|
|
|
|
self.assertTrue('media_player.bedroom' in result_json)
|
|
|
|
|
self.assertTrue('media_player.walkman' in result_json)
|
|
|
|
|
self.assertTrue('media_player.lounge_room' in result_json)
|
|
|
|
|
|
|
|
|
|
def test_get_light_state(self):
|
|
|
|
|
"""Test the getting of light state."""
|
|
|
|
|
# Turn office light on and set to 127 brightness
|
|
|
|
|
self.hass.services.call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_ON,
|
|
|
|
|
{
|
|
|
|
|
const.ATTR_ENTITY_ID: 'light.ceiling_lights',
|
|
|
|
|
light.ATTR_BRIGHTNESS: 127
|
|
|
|
|
},
|
|
|
|
|
blocking=True)
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_discover_lights(hue_client):
|
|
|
|
|
"""Test the discovery of lights."""
|
|
|
|
|
result = yield from hue_client.get('/api/username/lights')
|
|
|
|
|
|
|
|
|
|
office_json = self.perform_get_light_state('light.ceiling_lights', 200)
|
|
|
|
|
assert result.status == 200
|
|
|
|
|
assert 'application/json' in result.headers['content-type']
|
|
|
|
|
|
|
|
|
|
self.assertEqual(office_json['state'][HUE_API_STATE_ON], True)
|
|
|
|
|
self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127)
|
|
|
|
|
result_json = yield from result.json()
|
|
|
|
|
|
|
|
|
|
# Check all lights view
|
|
|
|
|
result = requests.get(
|
|
|
|
|
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5)
|
|
|
|
|
devices = set(val['uniqueid'] for val in result_json.values())
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
self.assertTrue('application/json' in result.headers['content-type'])
|
|
|
|
|
# Make sure the lights we added to the config are there
|
|
|
|
|
assert 'light.ceiling_lights' in devices
|
|
|
|
|
assert 'light.bed_light' in devices
|
|
|
|
|
assert 'script.set_kitchen_light' in devices
|
|
|
|
|
assert 'light.kitchen_lights' not in devices
|
|
|
|
|
assert 'media_player.living_room' in devices
|
|
|
|
|
assert 'media_player.bedroom' in devices
|
|
|
|
|
assert 'media_player.walkman' in devices
|
|
|
|
|
assert 'media_player.lounge_room' in devices
|
|
|
|
|
|
|
|
|
|
result_json = result.json()
|
|
|
|
|
|
|
|
|
|
self.assertTrue('light.ceiling_lights' in result_json)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
result_json['light.ceiling_lights']['state'][HUE_API_STATE_BRI],
|
|
|
|
|
127,
|
|
|
|
|
)
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_get_light_state(hass_hue, hue_client):
|
|
|
|
|
"""Test the getting of light state."""
|
|
|
|
|
# Turn office light on and set to 127 brightness
|
|
|
|
|
yield from hass_hue.services.async_call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_ON,
|
|
|
|
|
{
|
|
|
|
|
const.ATTR_ENTITY_ID: 'light.ceiling_lights',
|
|
|
|
|
light.ATTR_BRIGHTNESS: 127
|
|
|
|
|
},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
# Turn bedroom light off
|
|
|
|
|
self.hass.services.call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{
|
|
|
|
|
const.ATTR_ENTITY_ID: 'light.bed_light'
|
|
|
|
|
},
|
|
|
|
|
blocking=True)
|
|
|
|
|
office_json = yield from perform_get_light_state(
|
|
|
|
|
hue_client, 'light.ceiling_lights', 200)
|
|
|
|
|
|
|
|
|
|
bedroom_json = self.perform_get_light_state('light.bed_light', 200)
|
|
|
|
|
assert office_json['state'][HUE_API_STATE_ON] is True
|
|
|
|
|
assert office_json['state'][HUE_API_STATE_BRI] == 127
|
|
|
|
|
|
|
|
|
|
self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False)
|
|
|
|
|
self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0)
|
|
|
|
|
# Check all lights view
|
|
|
|
|
result = yield from hue_client.get('/api/username/lights')
|
|
|
|
|
|
|
|
|
|
# Make sure kitchen light isn't accessible
|
|
|
|
|
kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights')
|
|
|
|
|
kitchen_result = requests.get(
|
|
|
|
|
BRIDGE_URL_BASE.format(kitchen_url), timeout=5)
|
|
|
|
|
assert result.status == 200
|
|
|
|
|
assert 'application/json' in result.headers['content-type']
|
|
|
|
|
|
|
|
|
|
self.assertEqual(kitchen_result.status_code, 404)
|
|
|
|
|
result_json = yield from result.json()
|
|
|
|
|
|
|
|
|
|
def test_put_light_state(self):
|
|
|
|
|
"""Test the seeting of light states."""
|
|
|
|
|
self.perform_put_test_on_ceiling_lights()
|
|
|
|
|
assert 'light.ceiling_lights' in result_json
|
|
|
|
|
assert result_json['light.ceiling_lights']['state'][HUE_API_STATE_BRI] == \
|
|
|
|
|
127
|
|
|
|
|
|
|
|
|
|
# Turn the bedroom light on first
|
|
|
|
|
self.hass.services.call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_ON,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'light.bed_light',
|
|
|
|
|
light.ATTR_BRIGHTNESS: 153},
|
|
|
|
|
blocking=True)
|
|
|
|
|
# Turn bedroom light off
|
|
|
|
|
yield from hass_hue.services.async_call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{
|
|
|
|
|
const.ATTR_ENTITY_ID: 'light.bed_light'
|
|
|
|
|
},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
bed_light = self.hass.states.get('light.bed_light')
|
|
|
|
|
self.assertEqual(bed_light.state, STATE_ON)
|
|
|
|
|
self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153)
|
|
|
|
|
bedroom_json = yield from perform_get_light_state(
|
|
|
|
|
hue_client, 'light.bed_light', 200)
|
|
|
|
|
|
|
|
|
|
# Go through the API to turn it off
|
|
|
|
|
bedroom_result = self.perform_put_light_state(
|
|
|
|
|
'light.bed_light', False)
|
|
|
|
|
assert bedroom_json['state'][HUE_API_STATE_ON] is False
|
|
|
|
|
assert bedroom_json['state'][HUE_API_STATE_BRI] == 0
|
|
|
|
|
|
|
|
|
|
bedroom_result_json = bedroom_result.json()
|
|
|
|
|
# Make sure kitchen light isn't accessible
|
|
|
|
|
yield from perform_get_light_state(
|
|
|
|
|
hue_client, 'light.kitchen_lights', 404)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(bedroom_result.status_code, 200)
|
|
|
|
|
self.assertTrue(
|
|
|
|
|
'application/json' in bedroom_result.headers['content-type'])
|
|
|
|
|
|
|
|
|
|
self.assertEqual(len(bedroom_result_json), 1)
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_put_light_state(hass_hue, hue_client):
|
|
|
|
|
"""Test the seeting of light states."""
|
|
|
|
|
yield from perform_put_test_on_ceiling_lights(hass_hue, hue_client)
|
|
|
|
|
|
|
|
|
|
# Check to make sure the state changed
|
|
|
|
|
bed_light = self.hass.states.get('light.bed_light')
|
|
|
|
|
self.assertEqual(bed_light.state, STATE_OFF)
|
|
|
|
|
# Turn the bedroom light on first
|
|
|
|
|
yield from hass_hue.services.async_call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_ON,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'light.bed_light',
|
|
|
|
|
light.ATTR_BRIGHTNESS: 153},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
# Make sure we can't change the kitchen light state
|
|
|
|
|
kitchen_result = self.perform_put_light_state(
|
|
|
|
|
'light.kitchen_light', True)
|
|
|
|
|
self.assertEqual(kitchen_result.status_code, 404)
|
|
|
|
|
bed_light = hass_hue.states.get('light.bed_light')
|
|
|
|
|
assert bed_light.state == STATE_ON
|
|
|
|
|
assert bed_light.attributes[light.ATTR_BRIGHTNESS] == 153
|
|
|
|
|
|
|
|
|
|
def test_put_light_state_script(self):
|
|
|
|
|
"""Test the setting of script variables."""
|
|
|
|
|
# Turn the kitchen light off first
|
|
|
|
|
self.hass.services.call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'light.kitchen_lights'},
|
|
|
|
|
blocking=True)
|
|
|
|
|
# Go through the API to turn it off
|
|
|
|
|
bedroom_result = yield from perform_put_light_state(
|
|
|
|
|
hass_hue, hue_client,
|
|
|
|
|
'light.bed_light', False)
|
|
|
|
|
|
|
|
|
|
# Emulated hue converts 0-100% to 0-255.
|
|
|
|
|
level = 23
|
|
|
|
|
brightness = round(level * 255 / 100)
|
|
|
|
|
bedroom_result_json = yield from bedroom_result.json()
|
|
|
|
|
|
|
|
|
|
script_result = self.perform_put_light_state(
|
|
|
|
|
'script.set_kitchen_light', True, brightness)
|
|
|
|
|
assert bedroom_result.status == 200
|
|
|
|
|
assert 'application/json' in bedroom_result.headers['content-type']
|
|
|
|
|
|
|
|
|
|
script_result_json = script_result.json()
|
|
|
|
|
assert len(bedroom_result_json) == 1
|
|
|
|
|
|
|
|
|
|
self.assertEqual(script_result.status_code, 200)
|
|
|
|
|
self.assertEqual(len(script_result_json), 2)
|
|
|
|
|
# Check to make sure the state changed
|
|
|
|
|
bed_light = hass_hue.states.get('light.bed_light')
|
|
|
|
|
assert bed_light.state == STATE_OFF
|
|
|
|
|
|
|
|
|
|
kitchen_light = self.hass.states.get('light.kitchen_lights')
|
|
|
|
|
self.assertEqual(kitchen_light.state, 'on')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
kitchen_light.attributes[light.ATTR_BRIGHTNESS],
|
|
|
|
|
level)
|
|
|
|
|
# Make sure we can't change the kitchen light state
|
|
|
|
|
kitchen_result = yield from perform_put_light_state(
|
|
|
|
|
hass_hue, hue_client,
|
|
|
|
|
'light.kitchen_light', True)
|
|
|
|
|
assert kitchen_result.status == 404
|
|
|
|
|
|
|
|
|
|
def test_put_light_state_media_player(self):
|
|
|
|
|
"""Test turning on media player and setting volume."""
|
|
|
|
|
# Turn the music player off first
|
|
|
|
|
self.hass.services.call(
|
|
|
|
|
media_player.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'media_player.walkman'},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
# Emulated hue converts 0.0-1.0 to 0-255.
|
|
|
|
|
level = 0.25
|
|
|
|
|
brightness = round(level * 255)
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_put_light_state_script(hass_hue, hue_client):
|
|
|
|
|
"""Test the setting of script variables."""
|
|
|
|
|
# Turn the kitchen light off first
|
|
|
|
|
yield from hass_hue.services.async_call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'light.kitchen_lights'},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
mp_result = self.perform_put_light_state(
|
|
|
|
|
'media_player.walkman', True, brightness)
|
|
|
|
|
# Emulated hue converts 0-100% to 0-255.
|
|
|
|
|
level = 23
|
|
|
|
|
brightness = round(level * 255 / 100)
|
|
|
|
|
|
|
|
|
|
mp_result_json = mp_result.json()
|
|
|
|
|
script_result = yield from perform_put_light_state(
|
|
|
|
|
hass_hue, hue_client,
|
|
|
|
|
'script.set_kitchen_light', True, brightness)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(mp_result.status_code, 200)
|
|
|
|
|
self.assertEqual(len(mp_result_json), 2)
|
|
|
|
|
script_result_json = yield from script_result.json()
|
|
|
|
|
|
|
|
|
|
walkman = self.hass.states.get('media_player.walkman')
|
|
|
|
|
self.assertEqual(walkman.state, 'playing')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
walkman.attributes[media_player.ATTR_MEDIA_VOLUME_LEVEL],
|
|
|
|
|
level)
|
|
|
|
|
assert script_result.status == 200
|
|
|
|
|
assert len(script_result_json) == 2
|
|
|
|
|
|
|
|
|
|
# pylint: disable=invalid-name
|
|
|
|
|
def test_put_with_form_urlencoded_content_type(self):
|
|
|
|
|
"""Test the form with urlencoded content."""
|
|
|
|
|
# Needed for Alexa
|
|
|
|
|
self.perform_put_test_on_ceiling_lights(
|
|
|
|
|
'application/x-www-form-urlencoded')
|
|
|
|
|
kitchen_light = hass_hue.states.get('light.kitchen_lights')
|
|
|
|
|
assert kitchen_light.state == 'on'
|
|
|
|
|
assert kitchen_light.attributes[light.ATTR_BRIGHTNESS] == level
|
|
|
|
|
|
|
|
|
|
# Make sure we fail gracefully when we can't parse the data
|
|
|
|
|
data = {'key1': 'value1', 'key2': 'value2'}
|
|
|
|
|
result = requests.put(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}/state'.format(
|
|
|
|
|
'light.ceiling_lights')), data=data)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 400)
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_put_light_state_media_player(hass_hue, hue_client):
|
|
|
|
|
"""Test turning on media player and setting volume."""
|
|
|
|
|
# Turn the music player off first
|
|
|
|
|
yield from hass_hue.services.async_call(
|
|
|
|
|
media_player.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'media_player.walkman'},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
def test_entity_not_found(self):
|
|
|
|
|
"""Test for entity which are not found."""
|
|
|
|
|
result = requests.get(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}'.format("not.existant_entity")),
|
|
|
|
|
timeout=5)
|
|
|
|
|
# Emulated hue converts 0.0-1.0 to 0-255.
|
|
|
|
|
level = 0.25
|
|
|
|
|
brightness = round(level * 255)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
|
mp_result = yield from perform_put_light_state(
|
|
|
|
|
hass_hue, hue_client,
|
|
|
|
|
'media_player.walkman', True, brightness)
|
|
|
|
|
|
|
|
|
|
result = requests.put(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}/state'.format("non.existant_entity")),
|
|
|
|
|
timeout=5)
|
|
|
|
|
mp_result_json = yield from mp_result.json()
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
|
assert mp_result.status == 200
|
|
|
|
|
assert len(mp_result_json) == 2
|
|
|
|
|
|
|
|
|
|
def test_allowed_methods(self):
|
|
|
|
|
"""Test the allowed methods."""
|
|
|
|
|
result = requests.get(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}/state'.format(
|
|
|
|
|
"light.ceiling_lights")))
|
|
|
|
|
walkman = hass_hue.states.get('media_player.walkman')
|
|
|
|
|
assert walkman.state == 'playing'
|
|
|
|
|
assert walkman.attributes[media_player.ATTR_MEDIA_VOLUME_LEVEL] == level
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 405)
|
|
|
|
|
|
|
|
|
|
result = requests.put(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}'.format("light.ceiling_lights")),
|
|
|
|
|
data={'key1': 'value1'})
|
|
|
|
|
# pylint: disable=invalid-name
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_put_with_form_urlencoded_content_type(hass_hue, hue_client):
|
|
|
|
|
"""Test the form with urlencoded content."""
|
|
|
|
|
# Needed for Alexa
|
|
|
|
|
yield from perform_put_test_on_ceiling_lights(
|
|
|
|
|
hass_hue, hue_client, 'application/x-www-form-urlencoded')
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 405)
|
|
|
|
|
# Make sure we fail gracefully when we can't parse the data
|
|
|
|
|
data = {'key1': 'value1', 'key2': 'value2'}
|
|
|
|
|
result = yield from hue_client.put(
|
|
|
|
|
'/api/username/lights/light.ceiling_lights/state',
|
|
|
|
|
headers={
|
|
|
|
|
'content-type': 'application/x-www-form-urlencoded'
|
|
|
|
|
},
|
|
|
|
|
data=data,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = requests.put(
|
|
|
|
|
BRIDGE_URL_BASE.format('/api/username/lights'),
|
|
|
|
|
data={'key1': 'value1'})
|
|
|
|
|
assert result.status == 400
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 405)
|
|
|
|
|
|
|
|
|
|
def test_proper_put_state_request(self):
|
|
|
|
|
"""Test the request to set the state."""
|
|
|
|
|
# Test proper on value parsing
|
|
|
|
|
result = requests.put(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}/state'.format(
|
|
|
|
|
'light.ceiling_lights')),
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_entity_not_found(hue_client):
|
|
|
|
|
"""Test for entity which are not found."""
|
|
|
|
|
result = yield from hue_client.get(
|
|
|
|
|
'/api/username/lights/not.existant_entity')
|
|
|
|
|
|
|
|
|
|
assert result.status == 404
|
|
|
|
|
|
|
|
|
|
result = yield from hue_client.put(
|
|
|
|
|
'/api/username/lights/not.existant_entity/state')
|
|
|
|
|
|
|
|
|
|
assert result.status == 404
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_allowed_methods(hue_client):
|
|
|
|
|
"""Test the allowed methods."""
|
|
|
|
|
result = yield from hue_client.get(
|
|
|
|
|
'/api/username/lights/light.ceiling_lights/state')
|
|
|
|
|
|
|
|
|
|
assert result.status == 405
|
|
|
|
|
|
|
|
|
|
result = yield from hue_client.put(
|
|
|
|
|
'/api/username/lights/light.ceiling_lights')
|
|
|
|
|
|
|
|
|
|
assert result.status == 405
|
|
|
|
|
|
|
|
|
|
result = yield from hue_client.put(
|
|
|
|
|
'/api/username/lights')
|
|
|
|
|
|
|
|
|
|
assert result.status == 405
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def test_proper_put_state_request(hue_client):
|
|
|
|
|
"""Test the request to set the state."""
|
|
|
|
|
# Test proper on value parsing
|
|
|
|
|
result = yield from hue_client.put(
|
|
|
|
|
'/api/username/lights/{}/state'.format(
|
|
|
|
|
'light.ceiling_lights'),
|
|
|
|
|
data=json.dumps({HUE_API_STATE_ON: 1234}))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 400)
|
|
|
|
|
assert result.status == 400
|
|
|
|
|
|
|
|
|
|
# Test proper brightness value parsing
|
|
|
|
|
result = requests.put(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}/state'.format(
|
|
|
|
|
'light.ceiling_lights')), data=json.dumps({
|
|
|
|
|
HUE_API_STATE_ON: True,
|
|
|
|
|
HUE_API_STATE_BRI: 'Hello world!'
|
|
|
|
|
}))
|
|
|
|
|
# Test proper brightness value parsing
|
|
|
|
|
result = yield from hue_client.put(
|
|
|
|
|
'/api/username/lights/{}/state'.format(
|
|
|
|
|
'light.ceiling_lights'),
|
|
|
|
|
data=json.dumps({
|
|
|
|
|
HUE_API_STATE_ON: True,
|
|
|
|
|
HUE_API_STATE_BRI: 'Hello world!'
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 400)
|
|
|
|
|
assert result.status == 400
|
|
|
|
|
|
|
|
|
|
# pylint: disable=invalid-name
|
|
|
|
|
def perform_put_test_on_ceiling_lights(self,
|
|
|
|
|
content_type='application/json'):
|
|
|
|
|
"""Test the setting of a light."""
|
|
|
|
|
# Turn the office light off first
|
|
|
|
|
self.hass.services.call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
ceiling_lights = self.hass.states.get('light.ceiling_lights')
|
|
|
|
|
self.assertEqual(ceiling_lights.state, STATE_OFF)
|
|
|
|
|
# pylint: disable=invalid-name
|
|
|
|
|
def perform_put_test_on_ceiling_lights(hass_hue, hue_client,
|
|
|
|
|
content_type='application/json'):
|
|
|
|
|
"""Test the setting of a light."""
|
|
|
|
|
# Turn the office light off first
|
|
|
|
|
yield from hass_hue.services.async_call(
|
|
|
|
|
light.DOMAIN, const.SERVICE_TURN_OFF,
|
|
|
|
|
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
|
|
|
|
|
blocking=True)
|
|
|
|
|
|
|
|
|
|
# Go through the API to turn it on
|
|
|
|
|
office_result = self.perform_put_light_state(
|
|
|
|
|
'light.ceiling_lights', True, 56, content_type)
|
|
|
|
|
ceiling_lights = hass_hue.states.get('light.ceiling_lights')
|
|
|
|
|
assert ceiling_lights.state == STATE_OFF
|
|
|
|
|
|
|
|
|
|
office_result_json = office_result.json()
|
|
|
|
|
# Go through the API to turn it on
|
|
|
|
|
office_result = yield from perform_put_light_state(
|
|
|
|
|
hass_hue, hue_client,
|
|
|
|
|
'light.ceiling_lights', True, 56, content_type)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(office_result.status_code, 200)
|
|
|
|
|
self.assertTrue(
|
|
|
|
|
'application/json' in office_result.headers['content-type'])
|
|
|
|
|
assert office_result.status == 200
|
|
|
|
|
assert 'application/json' in office_result.headers['content-type']
|
|
|
|
|
|
|
|
|
|
self.assertEqual(len(office_result_json), 2)
|
|
|
|
|
office_result_json = yield from office_result.json()
|
|
|
|
|
|
|
|
|
|
# Check to make sure the state changed
|
|
|
|
|
ceiling_lights = self.hass.states.get('light.ceiling_lights')
|
|
|
|
|
self.assertEqual(ceiling_lights.state, STATE_ON)
|
|
|
|
|
self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56)
|
|
|
|
|
assert len(office_result_json) == 2
|
|
|
|
|
|
|
|
|
|
def perform_get_light_state(self, entity_id, expected_status):
|
|
|
|
|
"""Test the gettting of a light state."""
|
|
|
|
|
result = requests.get(
|
|
|
|
|
BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}'.format(entity_id)), timeout=5)
|
|
|
|
|
# Check to make sure the state changed
|
|
|
|
|
ceiling_lights = hass_hue.states.get('light.ceiling_lights')
|
|
|
|
|
assert ceiling_lights.state == STATE_ON
|
|
|
|
|
assert ceiling_lights.attributes[light.ATTR_BRIGHTNESS] == 56
|
|
|
|
|
|
|
|
|
|
self.assertEqual(result.status_code, expected_status)
|
|
|
|
|
|
|
|
|
|
if expected_status == 200:
|
|
|
|
|
self.assertTrue(
|
|
|
|
|
'application/json' in result.headers['content-type'])
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def perform_get_light_state(client, entity_id, expected_status):
|
|
|
|
|
"""Test the gettting of a light state."""
|
|
|
|
|
result = yield from client.get('/api/username/lights/{}'.format(entity_id))
|
|
|
|
|
|
|
|
|
|
return result.json()
|
|
|
|
|
assert result.status == expected_status
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
if expected_status == 200:
|
|
|
|
|
assert 'application/json' in result.headers['content-type']
|
|
|
|
|
|
|
|
|
|
# pylint: disable=no-self-use
|
|
|
|
|
def perform_put_light_state(self, entity_id, is_on, brightness=None,
|
|
|
|
|
content_type='application/json'):
|
|
|
|
|
"""Test the setting of a light state."""
|
|
|
|
|
url = BRIDGE_URL_BASE.format(
|
|
|
|
|
'/api/username/lights/{}/state'.format(entity_id))
|
|
|
|
|
return (yield from result.json())
|
|
|
|
|
|
|
|
|
|
req_headers = {'Content-Type': content_type}
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
data = {HUE_API_STATE_ON: is_on}
|
|
|
|
|
|
|
|
|
|
if brightness is not None:
|
|
|
|
|
data[HUE_API_STATE_BRI] = brightness
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
|
def perform_put_light_state(hass_hue, client, entity_id, is_on,
|
|
|
|
|
brightness=None, content_type='application/json'):
|
|
|
|
|
"""Test the setting of a light state."""
|
|
|
|
|
req_headers = {'Content-Type': content_type}
|
|
|
|
|
|
|
|
|
|
result = requests.put(
|
|
|
|
|
url, data=json.dumps(data), timeout=5, headers=req_headers)
|
|
|
|
|
data = {HUE_API_STATE_ON: is_on}
|
|
|
|
|
|
|
|
|
|
# Wait until state change is complete before continuing
|
|
|
|
|
self.hass.block_till_done()
|
|
|
|
|
if brightness is not None:
|
|
|
|
|
data[HUE_API_STATE_BRI] = brightness
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
result = yield from client.put(
|
|
|
|
|
'/api/username/lights/{}/state'.format(entity_id), headers=req_headers,
|
|
|
|
|
data=json.dumps(data).encode())
|
|
|
|
|
|
|
|
|
|
# Wait until state change is complete before continuing
|
|
|
|
|
yield from hass_hue.async_block_till_done()
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|