mirror of
https://github.com/home-assistant/core.git
synced 2025-08-02 18:18:21 +00:00
Allow emulated hue to set climate component temperature (#19034)
This commit is contained in:
parent
5debc8828a
commit
77dc7595ee
@ -1,4 +1,4 @@
|
|||||||
"""Proides the constants needed for component."""
|
"""Provides the constants needed for component."""
|
||||||
|
|
||||||
ATTR_AUX_HEAT = 'aux_heat'
|
ATTR_AUX_HEAT = 'aux_heat'
|
||||||
ATTR_AWAY_MODE = 'away_mode'
|
ATTR_AWAY_MODE = 'away_mode'
|
||||||
|
@ -5,13 +5,16 @@ from aiohttp import web
|
|||||||
|
|
||||||
from homeassistant import core
|
from homeassistant import core
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_SET,
|
ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
||||||
SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, STATE_ON, STATE_OFF,
|
SERVICE_VOLUME_SET, SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, STATE_ON,
|
||||||
HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ATTR_SUPPORTED_FEATURES,
|
STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ATTR_SUPPORTED_FEATURES
|
||||||
)
|
)
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS
|
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.climate.const import (
|
||||||
|
SERVICE_SET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE
|
||||||
|
)
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
ATTR_MEDIA_VOLUME_LEVEL, SUPPORT_VOLUME_SET,
|
ATTR_MEDIA_VOLUME_LEVEL, SUPPORT_VOLUME_SET,
|
||||||
)
|
)
|
||||||
@ -26,7 +29,7 @@ from homeassistant.components.cover import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components import (
|
from homeassistant.components import (
|
||||||
cover, fan, media_player, light, script, scene
|
climate, cover, fan, media_player, light, script, scene
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components.http import HomeAssistantView
|
from homeassistant.components.http import HomeAssistantView
|
||||||
@ -262,6 +265,18 @@ class HueOneLightChangeView(HomeAssistantView):
|
|||||||
if brightness is not None:
|
if brightness is not None:
|
||||||
data['variables']['requested_level'] = brightness
|
data['variables']['requested_level'] = brightness
|
||||||
|
|
||||||
|
# If the requested entity is a climate, set the temperature
|
||||||
|
elif entity.domain == climate.DOMAIN:
|
||||||
|
# We don't support turning climate devices on or off,
|
||||||
|
# only setting the temperature
|
||||||
|
service = None
|
||||||
|
|
||||||
|
if entity_features & SUPPORT_TARGET_TEMPERATURE:
|
||||||
|
if brightness is not None:
|
||||||
|
domain = entity.domain
|
||||||
|
service = SERVICE_SET_TEMPERATURE
|
||||||
|
data[ATTR_TEMPERATURE] = brightness
|
||||||
|
|
||||||
# If the requested entity is a media player, convert to volume
|
# If the requested entity is a media player, convert to volume
|
||||||
elif entity.domain == media_player.DOMAIN:
|
elif entity.domain == media_player.DOMAIN:
|
||||||
if entity_features & SUPPORT_VOLUME_SET:
|
if entity_features & SUPPORT_VOLUME_SET:
|
||||||
@ -318,8 +333,9 @@ class HueOneLightChangeView(HomeAssistantView):
|
|||||||
core.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id},
|
core.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id},
|
||||||
blocking=True))
|
blocking=True))
|
||||||
|
|
||||||
hass.async_create_task(hass.services.async_call(
|
if service is not None:
|
||||||
domain, service, data, blocking=True))
|
hass.async_create_task(hass.services.async_call(
|
||||||
|
domain, service, data, blocking=True))
|
||||||
|
|
||||||
json_response = \
|
json_response = \
|
||||||
[create_hue_success_response(entity_id, HUE_API_STATE_ON, result)]
|
[create_hue_success_response(entity_id, HUE_API_STATE_ON, result)]
|
||||||
@ -371,7 +387,7 @@ def parse_hue_api_put_light_body(request_json, entity):
|
|||||||
|
|
||||||
elif entity.domain in [
|
elif entity.domain in [
|
||||||
script.DOMAIN, media_player.DOMAIN,
|
script.DOMAIN, media_player.DOMAIN,
|
||||||
fan.DOMAIN, cover.DOMAIN]:
|
fan.DOMAIN, cover.DOMAIN, climate.DOMAIN]:
|
||||||
# Convert 0-255 to 0-100
|
# Convert 0-255 to 0-100
|
||||||
level = brightness / 255 * 100
|
level = brightness / 255 * 100
|
||||||
brightness = round(level)
|
brightness = round(level)
|
||||||
@ -397,6 +413,10 @@ def get_entity_state(config, entity):
|
|||||||
if entity_features & SUPPORT_BRIGHTNESS:
|
if entity_features & SUPPORT_BRIGHTNESS:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
elif entity.domain == climate.DOMAIN:
|
||||||
|
temperature = entity.attributes.get(ATTR_TEMPERATURE, 0)
|
||||||
|
# Convert 0-100 to 0-255
|
||||||
|
final_brightness = round(temperature * 255 / 100)
|
||||||
elif entity.domain == media_player.DOMAIN:
|
elif entity.domain == media_player.DOMAIN:
|
||||||
level = entity.attributes.get(
|
level = entity.attributes.get(
|
||||||
ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0)
|
ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0)
|
||||||
|
@ -11,7 +11,7 @@ from tests.common import get_test_instance_port
|
|||||||
from homeassistant import core, const, setup
|
from homeassistant import core, const, setup
|
||||||
import homeassistant.components as core_components
|
import homeassistant.components as core_components
|
||||||
from homeassistant.components import (
|
from homeassistant.components import (
|
||||||
fan, http, light, script, emulated_hue, media_player, cover)
|
fan, http, light, script, emulated_hue, media_player, cover, climate)
|
||||||
from homeassistant.components.emulated_hue import Config
|
from homeassistant.components.emulated_hue import Config
|
||||||
from homeassistant.components.emulated_hue.hue_api import (
|
from homeassistant.components.emulated_hue.hue_api import (
|
||||||
HUE_API_STATE_ON, HUE_API_STATE_BRI, HueUsernameView, HueOneLightStateView,
|
HUE_API_STATE_ON, HUE_API_STATE_BRI, HueUsernameView, HueOneLightStateView,
|
||||||
@ -77,6 +77,15 @@ def hass_hue(loop, hass):
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
loop.run_until_complete(
|
||||||
|
setup.async_setup_component(hass, climate.DOMAIN, {
|
||||||
|
'climate': [
|
||||||
|
{
|
||||||
|
'platform': 'demo',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
|
||||||
loop.run_until_complete(
|
loop.run_until_complete(
|
||||||
setup.async_setup_component(hass, media_player.DOMAIN, {
|
setup.async_setup_component(hass, media_player.DOMAIN, {
|
||||||
'media_player': [
|
'media_player': [
|
||||||
@ -136,6 +145,22 @@ def hass_hue(loop, hass):
|
|||||||
cover_entity.entity_id, cover_entity.state, attributes=attrs
|
cover_entity.entity_id, cover_entity.state, attributes=attrs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Expose Hvac
|
||||||
|
hvac_entity = hass.states.get('climate.hvac')
|
||||||
|
attrs = dict(hvac_entity.attributes)
|
||||||
|
attrs[emulated_hue.ATTR_EMULATED_HUE_HIDDEN] = False
|
||||||
|
hass.states.async_set(
|
||||||
|
hvac_entity.entity_id, hvac_entity.state, attributes=attrs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Expose HeatPump
|
||||||
|
hp_entity = hass.states.get('climate.heatpump')
|
||||||
|
attrs = dict(hp_entity.attributes)
|
||||||
|
attrs[emulated_hue.ATTR_EMULATED_HUE_HIDDEN] = False
|
||||||
|
hass.states.async_set(
|
||||||
|
hp_entity.entity_id, hp_entity.state, attributes=attrs
|
||||||
|
)
|
||||||
|
|
||||||
return hass
|
return hass
|
||||||
|
|
||||||
|
|
||||||
@ -189,6 +214,9 @@ def test_discover_lights(hue_client):
|
|||||||
assert 'fan.living_room_fan' in devices
|
assert 'fan.living_room_fan' in devices
|
||||||
assert 'fan.ceiling_fan' not in devices
|
assert 'fan.ceiling_fan' not in devices
|
||||||
assert 'cover.living_room_window' in devices
|
assert 'cover.living_room_window' in devices
|
||||||
|
assert 'climate.hvac' in devices
|
||||||
|
assert 'climate.heatpump' in devices
|
||||||
|
assert 'climate.ecobee' not in devices
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@ -316,6 +344,84 @@ def test_put_light_state_script(hass_hue, hue_client):
|
|||||||
assert kitchen_light.attributes[light.ATTR_BRIGHTNESS] == level
|
assert kitchen_light.attributes[light.ATTR_BRIGHTNESS] == level
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_put_light_state_climate_set_temperature(hass_hue, hue_client):
|
||||||
|
"""Test setting climate temperature."""
|
||||||
|
brightness = 19
|
||||||
|
temperature = round(brightness / 255 * 100)
|
||||||
|
|
||||||
|
hvac_result = yield from perform_put_light_state(
|
||||||
|
hass_hue, hue_client,
|
||||||
|
'climate.hvac', True, brightness)
|
||||||
|
|
||||||
|
hvac_result_json = yield from hvac_result.json()
|
||||||
|
|
||||||
|
assert hvac_result.status == 200
|
||||||
|
assert len(hvac_result_json) == 2
|
||||||
|
|
||||||
|
hvac = hass_hue.states.get('climate.hvac')
|
||||||
|
assert hvac.state == climate.const.STATE_COOL
|
||||||
|
assert hvac.attributes[climate.ATTR_TEMPERATURE] == temperature
|
||||||
|
assert hvac.attributes[climate.ATTR_OPERATION_MODE] == \
|
||||||
|
climate.const.STATE_COOL
|
||||||
|
|
||||||
|
# Make sure we can't change the ecobee temperature since it's not exposed
|
||||||
|
ecobee_result = yield from perform_put_light_state(
|
||||||
|
hass_hue, hue_client,
|
||||||
|
'climate.ecobee', True)
|
||||||
|
assert ecobee_result.status == 404
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_put_light_state_climate_turn_on(hass_hue, hue_client):
|
||||||
|
"""Test inability to turn climate on."""
|
||||||
|
yield from hass_hue.services.async_call(
|
||||||
|
climate.DOMAIN, const.SERVICE_TURN_OFF,
|
||||||
|
{const.ATTR_ENTITY_ID: 'climate.heatpump'},
|
||||||
|
blocking=True)
|
||||||
|
|
||||||
|
# Somehow after calling the above service the device gets unexposed,
|
||||||
|
# so we need to expose it again
|
||||||
|
hp_entity = hass_hue.states.get('climate.heatpump')
|
||||||
|
attrs = dict(hp_entity.attributes)
|
||||||
|
attrs[emulated_hue.ATTR_EMULATED_HUE_HIDDEN] = False
|
||||||
|
hass_hue.states.async_set(
|
||||||
|
hp_entity.entity_id, hp_entity.state, attributes=attrs
|
||||||
|
)
|
||||||
|
|
||||||
|
hp_result = yield from perform_put_light_state(
|
||||||
|
hass_hue, hue_client,
|
||||||
|
'climate.heatpump', True)
|
||||||
|
|
||||||
|
hp_result_json = yield from hp_result.json()
|
||||||
|
|
||||||
|
assert hp_result.status == 200
|
||||||
|
assert len(hp_result_json) == 1
|
||||||
|
|
||||||
|
hp = hass_hue.states.get('climate.heatpump')
|
||||||
|
assert hp.state == STATE_OFF
|
||||||
|
assert hp.attributes[climate.ATTR_OPERATION_MODE] == \
|
||||||
|
climate.const.STATE_HEAT
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_put_light_state_climate_turn_off(hass_hue, hue_client):
|
||||||
|
"""Test inability to turn climate off."""
|
||||||
|
hp_result = yield from perform_put_light_state(
|
||||||
|
hass_hue, hue_client,
|
||||||
|
'climate.heatpump', False)
|
||||||
|
|
||||||
|
hp_result_json = yield from hp_result.json()
|
||||||
|
|
||||||
|
assert hp_result.status == 200
|
||||||
|
assert len(hp_result_json) == 1
|
||||||
|
|
||||||
|
hp = hass_hue.states.get('climate.heatpump')
|
||||||
|
assert hp.state == climate.const.STATE_HEAT
|
||||||
|
assert hp.attributes[climate.ATTR_OPERATION_MODE] == \
|
||||||
|
climate.const.STATE_HEAT
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_put_light_state_media_player(hass_hue, hue_client):
|
def test_put_light_state_media_player(hass_hue, hue_client):
|
||||||
"""Test turning on media player and setting volume."""
|
"""Test turning on media player and setting volume."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user