Set cover level using emulated_hue (#19594)

* set cover level using emulated_hue

* changed mapping for service turn_on/off for cover.

* removed whitespace for the sake of hound

* using const for domains instead of hardcoded strings.

* change length of lines for the sake of hound

* fixed under-intended line

* changed intent for the sake of hound
pull/20990/head
Patrick T.C 2019-02-11 19:59:34 +01:00 committed by Charles Garwood
parent 788f7988e7
commit 49ecca9cb9
2 changed files with 151 additions and 14 deletions

View File

@ -19,6 +19,16 @@ from homeassistant.components.fan import (
ATTR_SPEED, SUPPORT_SET_SPEED, SPEED_OFF, SPEED_LOW,
SPEED_MEDIUM, SPEED_HIGH
)
from homeassistant.components.cover import (
ATTR_CURRENT_POSITION, ATTR_POSITION, SERVICE_SET_COVER_POSITION,
SUPPORT_SET_POSITION
)
from homeassistant.components import (
cover, fan, media_player, light, script, scene
)
from homeassistant.components.http import HomeAssistantView
from homeassistant.components.http.const import KEY_REAL_IP
from homeassistant.util.network import is_local
@ -239,13 +249,13 @@ class HueOneLightChangeView(HomeAssistantView):
# Make sure the entity actually supports brightness
entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if entity.domain == "light":
if entity.domain == light.DOMAIN:
if entity_features & SUPPORT_BRIGHTNESS:
if brightness is not None:
data[ATTR_BRIGHTNESS] = brightness
# If the requested entity is a script add some variables
elif entity.domain == "script":
elif entity.domain == script.DOMAIN:
data['variables'] = {
'requested_state': STATE_ON if result else STATE_OFF
}
@ -254,7 +264,7 @@ class HueOneLightChangeView(HomeAssistantView):
data['variables']['requested_level'] = brightness
# If the requested entity is a media player, convert to volume
elif entity.domain == "media_player":
elif entity.domain == media_player.DOMAIN:
if entity_features & SUPPORT_VOLUME_SET:
if brightness is not None:
turn_on_needed = True
@ -264,15 +274,21 @@ class HueOneLightChangeView(HomeAssistantView):
data[ATTR_MEDIA_VOLUME_LEVEL] = brightness / 100.0
# If the requested entity is a cover, convert to open_cover/close_cover
elif entity.domain == "cover":
elif entity.domain == cover.DOMAIN:
domain = entity.domain
if service == SERVICE_TURN_ON:
service = SERVICE_OPEN_COVER
else:
service = SERVICE_CLOSE_COVER
if entity_features & SUPPORT_SET_POSITION:
if brightness is not None:
domain = entity.domain
service = SERVICE_SET_COVER_POSITION
data[ATTR_POSITION] = brightness
# If the requested entity is a fan, convert to speed
elif entity.domain == "fan":
elif entity.domain == fan.DOMAIN:
if entity_features & SUPPORT_SET_SPEED:
if brightness is not None:
domain = entity.domain
@ -344,19 +360,19 @@ def parse_hue_api_put_light_body(request_json, entity):
# Make sure the entity actually supports brightness
entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if entity.domain == "light":
if entity.domain == light.DOMAIN:
if entity_features & SUPPORT_BRIGHTNESS:
report_brightness = True
result = (brightness > 0)
elif entity.domain == "scene":
elif entity.domain == scene.DOMAIN:
brightness = None
report_brightness = False
result = True
elif (entity.domain == "script" or
entity.domain == "media_player" or
entity.domain == "fan"):
elif entity.domain in [
script.DOMAIN, media_player.DOMAIN,
fan.DOMAIN, cover.DOMAIN]:
# Convert 0-255 to 0-100
level = brightness / 255 * 100
brightness = round(level)
@ -378,16 +394,16 @@ def get_entity_state(config, entity):
# Make sure the entity actually supports brightness
entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if entity.domain == "light":
if entity.domain == light.DOMAIN:
if entity_features & SUPPORT_BRIGHTNESS:
pass
elif entity.domain == "media_player":
elif entity.domain == media_player.DOMAIN:
level = entity.attributes.get(
ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0)
# Convert 0.0-1.0 to 0-255
final_brightness = round(min(1.0, level) * 255)
elif entity.domain == "fan":
elif entity.domain == fan.DOMAIN:
speed = entity.attributes.get(ATTR_SPEED, 0)
# Convert 0.0-1.0 to 0-255
final_brightness = 0
@ -397,6 +413,9 @@ def get_entity_state(config, entity):
final_brightness = 170
elif speed == SPEED_HIGH:
final_brightness = 255
elif entity.domain == cover.DOMAIN:
level = entity.attributes.get(ATTR_CURRENT_POSITION, 0)
final_brightness = round(level / 100 * 255)
else:
final_state, final_brightness = cached_state
# Make sure brightness is valid

View File

@ -11,13 +11,17 @@ from tests.common import get_test_instance_port
from homeassistant import core, const, setup
import homeassistant.components as core_components
from homeassistant.components import (
fan, http, light, script, emulated_hue, media_player)
fan, http, light, script, emulated_hue, media_player, cover)
from homeassistant.components.emulated_hue import Config
from homeassistant.components.emulated_hue.hue_api import (
HUE_API_STATE_ON, HUE_API_STATE_BRI, HueUsernameView, HueOneLightStateView,
HueAllLightsStateView, HueOneLightChangeView, HueAllGroupsStateView)
from homeassistant.const import STATE_ON, STATE_OFF
import homeassistant.util.dt as dt_util
from datetime import timedelta
from tests.common import async_fire_time_changed
HTTP_SERVER_PORT = get_test_instance_port()
BRIDGE_SERVER_PORT = get_test_instance_port()
@ -91,6 +95,15 @@ def hass_hue(loop, hass):
]
}))
loop.run_until_complete(
setup.async_setup_component(hass, cover.DOMAIN, {
'cover': [
{
'platform': 'demo',
}
]
}))
# Kitchen light is explicitly excluded from being exposed
kitchen_light_entity = hass.states.get('light.kitchen_lights')
attrs = dict(kitchen_light_entity.attributes)
@ -115,6 +128,14 @@ def hass_hue(loop, hass):
script_entity.entity_id, script_entity.state, attributes=attrs
)
# Expose cover
cover_entity = hass.states.get('cover.living_room_window')
attrs = dict(cover_entity.attributes)
attrs[emulated_hue.ATTR_EMULATED_HUE_HIDDEN] = False
hass.states.async_set(
cover_entity.entity_id, cover_entity.state, attributes=attrs
)
return hass
@ -127,7 +148,11 @@ def hue_client(loop, hass_hue, aiohttp_client):
emulated_hue.CONF_ENTITIES: {
'light.bed_light': {
emulated_hue.CONF_ENTITY_HIDDEN: True
},
'cover.living_room_window': {
emulated_hue.CONF_ENTITY_HIDDEN: False
}
}
})
@ -163,6 +188,7 @@ def test_discover_lights(hue_client):
assert 'media_player.lounge_room' in devices
assert 'fan.living_room_fan' in devices
assert 'fan.ceiling_fan' not in devices
assert 'cover.living_room_window' in devices
@asyncio.coroutine
@ -317,6 +343,98 @@ def test_put_light_state_media_player(hass_hue, hue_client):
assert walkman.attributes[media_player.ATTR_MEDIA_VOLUME_LEVEL] == level
async def test_close_cover(hass_hue, hue_client):
"""Test opening cover ."""
COVER_ID = "cover.living_room_window"
# Turn the office light off first
await hass_hue.services.async_call(
cover.DOMAIN, const.SERVICE_CLOSE_COVER,
{const.ATTR_ENTITY_ID: COVER_ID},
blocking=True)
cover_test = hass_hue.states.get(COVER_ID)
assert cover_test.state == 'closing'
for _ in range(7):
future = dt_util.utcnow() + timedelta(seconds=1)
async_fire_time_changed(hass_hue, future)
await hass_hue.async_block_till_done()
cover_test = hass_hue.states.get(COVER_ID)
assert cover_test.state == 'closed'
# Go through the API to turn it on
cover_result = await perform_put_light_state(
hass_hue, hue_client,
COVER_ID, True, 100)
assert cover_result.status == 200
assert 'application/json' in cover_result.headers['content-type']
for _ in range(7):
future = dt_util.utcnow() + timedelta(seconds=1)
async_fire_time_changed(hass_hue, future)
await hass_hue.async_block_till_done()
cover_result_json = await cover_result.json()
assert len(cover_result_json) == 2
# Check to make sure the state changed
cover_test_2 = hass_hue.states.get(COVER_ID)
assert cover_test_2.state == 'open'
async def test_set_position_cover(hass_hue, hue_client):
"""Test setting postion cover ."""
COVER_ID = "cover.living_room_window"
# Turn the office light off first
await hass_hue.services.async_call(
cover.DOMAIN, const.SERVICE_CLOSE_COVER,
{const.ATTR_ENTITY_ID: COVER_ID},
blocking=True)
cover_test = hass_hue.states.get(COVER_ID)
assert cover_test.state == 'closing'
for _ in range(7):
future = dt_util.utcnow() + timedelta(seconds=1)
async_fire_time_changed(hass_hue, future)
await hass_hue.async_block_till_done()
cover_test = hass_hue.states.get(COVER_ID)
assert cover_test.state == 'closed'
level = 20
brightness = round(level/100*255)
# Go through the API to open
cover_result = await perform_put_light_state(
hass_hue, hue_client,
COVER_ID, False, brightness)
assert cover_result.status == 200
assert 'application/json' in cover_result.headers['content-type']
cover_result_json = await cover_result.json()
assert len(cover_result_json) == 2
assert True, cover_result_json[0]['success'][
'/lights/cover.living_room_window/state/on']
assert cover_result_json[1]['success'][
'/lights/cover.living_room_window/state/bri'] == level
for _ in range(100):
future = dt_util.utcnow() + timedelta(seconds=1)
async_fire_time_changed(hass_hue, future)
await hass_hue.async_block_till_done()
# Check to make sure the state changed
cover_test_2 = hass_hue.states.get(COVER_ID)
assert cover_test_2.state == 'open'
assert cover_test_2.attributes.get('current_position') == level
@asyncio.coroutine
def test_put_light_state_fan(hass_hue, hue_client):
"""Test turning on fan and setting speed."""