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 houndpull/20990/head
parent
788f7988e7
commit
49ecca9cb9
|
@ -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
|
||||
|
|
|
@ -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."""
|
||||
|
|
Loading…
Reference in New Issue