mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Handle on/off through TemperatrureSetting trait. (#21842)
This commit is contained in:
parent
fe468ace34
commit
81bb928394
@ -21,6 +21,7 @@ from homeassistant.const import (
|
|||||||
SERVICE_TURN_ON,
|
SERVICE_TURN_ON,
|
||||||
STATE_LOCKED,
|
STATE_LOCKED,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
|
STATE_ON,
|
||||||
TEMP_CELSIUS,
|
TEMP_CELSIUS,
|
||||||
TEMP_FAHRENHEIT,
|
TEMP_FAHRENHEIT,
|
||||||
ATTR_SUPPORTED_FEATURES,
|
ATTR_SUPPORTED_FEATURES,
|
||||||
@ -199,8 +200,6 @@ class OnOffTrait(_Trait):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def supported(domain, features):
|
def supported(domain, features):
|
||||||
"""Test if state is supported."""
|
"""Test if state is supported."""
|
||||||
if domain == climate.DOMAIN:
|
|
||||||
return features & climate.SUPPORT_ON_OFF != 0
|
|
||||||
return domain in (
|
return domain in (
|
||||||
group.DOMAIN,
|
group.DOMAIN,
|
||||||
input_boolean.DOMAIN,
|
input_boolean.DOMAIN,
|
||||||
@ -537,9 +536,17 @@ class TemperatureSettingTrait(_Trait):
|
|||||||
def sync_attributes(self):
|
def sync_attributes(self):
|
||||||
"""Return temperature point and modes attributes for a sync request."""
|
"""Return temperature point and modes attributes for a sync request."""
|
||||||
modes = []
|
modes = []
|
||||||
for mode in self.state.attributes.get(climate.ATTR_OPERATION_LIST, []):
|
supported = self.state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||||
|
|
||||||
|
if supported & climate.SUPPORT_ON_OFF != 0:
|
||||||
|
modes.append(STATE_OFF)
|
||||||
|
modes.append(STATE_ON)
|
||||||
|
|
||||||
|
if supported & climate.SUPPORT_OPERATION_MODE != 0:
|
||||||
|
for mode in self.state.attributes.get(climate.ATTR_OPERATION_LIST,
|
||||||
|
[]):
|
||||||
google_mode = self.hass_to_google.get(mode)
|
google_mode = self.hass_to_google.get(mode)
|
||||||
if google_mode is not None:
|
if google_mode and google_mode not in modes:
|
||||||
modes.append(google_mode)
|
modes.append(google_mode)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -554,8 +561,16 @@ class TemperatureSettingTrait(_Trait):
|
|||||||
response = {}
|
response = {}
|
||||||
|
|
||||||
operation = attrs.get(climate.ATTR_OPERATION_MODE)
|
operation = attrs.get(climate.ATTR_OPERATION_MODE)
|
||||||
if operation is not None and operation in self.hass_to_google:
|
supported = self.state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||||
|
|
||||||
|
if (supported & climate.SUPPORT_ON_OFF
|
||||||
|
and self.state.state == STATE_OFF):
|
||||||
|
response['thermostatMode'] = 'off'
|
||||||
|
elif (supported & climate.SUPPORT_OPERATION_MODE and
|
||||||
|
operation in self.hass_to_google):
|
||||||
response['thermostatMode'] = self.hass_to_google[operation]
|
response['thermostatMode'] = self.hass_to_google[operation]
|
||||||
|
elif supported & climate.SUPPORT_ON_OFF:
|
||||||
|
response['thermostatMode'] = 'on'
|
||||||
|
|
||||||
unit = self.hass.config.units.temperature_unit
|
unit = self.hass.config.units.temperature_unit
|
||||||
|
|
||||||
@ -644,11 +659,26 @@ class TemperatureSettingTrait(_Trait):
|
|||||||
}, blocking=True, context=data.context)
|
}, blocking=True, context=data.context)
|
||||||
|
|
||||||
elif command == COMMAND_THERMOSTAT_SET_MODE:
|
elif command == COMMAND_THERMOSTAT_SET_MODE:
|
||||||
|
target_mode = params['thermostatMode']
|
||||||
|
supported = self.state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||||
|
|
||||||
|
if (target_mode in [STATE_ON, STATE_OFF] and
|
||||||
|
supported & climate.SUPPORT_ON_OFF):
|
||||||
|
await self.hass.services.async_call(
|
||||||
|
climate.DOMAIN,
|
||||||
|
(SERVICE_TURN_ON
|
||||||
|
if target_mode == STATE_ON
|
||||||
|
else SERVICE_TURN_OFF),
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: self.state.entity_id,
|
||||||
|
climate.ATTR_OPERATION_MODE: target_mode,
|
||||||
|
}, blocking=True, context=data.context)
|
||||||
|
elif supported & climate.SUPPORT_OPERATION_MODE:
|
||||||
await self.hass.services.async_call(
|
await self.hass.services.async_call(
|
||||||
climate.DOMAIN, climate.SERVICE_SET_OPERATION_MODE, {
|
climate.DOMAIN, climate.SERVICE_SET_OPERATION_MODE, {
|
||||||
ATTR_ENTITY_ID: self.state.entity_id,
|
ATTR_ENTITY_ID: self.state.entity_id,
|
||||||
climate.ATTR_OPERATION_MODE:
|
climate.ATTR_OPERATION_MODE:
|
||||||
self.google_to_hass[params['thermostatMode']],
|
self.google_to_hass[target_mode],
|
||||||
}, blocking=True, context=data.context)
|
}, blocking=True, context=data.context)
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,10 +231,7 @@ DEMO_DEVICES = [{
|
|||||||
'name': {
|
'name': {
|
||||||
'name': 'HeatPump'
|
'name': 'HeatPump'
|
||||||
},
|
},
|
||||||
'traits': [
|
'traits': ['action.devices.traits.TemperatureSetting'],
|
||||||
'action.devices.traits.OnOff',
|
|
||||||
'action.devices.traits.TemperatureSetting'
|
|
||||||
],
|
|
||||||
'type': 'action.devices.types.THERMOSTAT',
|
'type': 'action.devices.types.THERMOSTAT',
|
||||||
'willReportState': False
|
'willReportState': False
|
||||||
}, {
|
}, {
|
||||||
|
@ -205,7 +205,6 @@ def test_query_climate_request(hass_fixture, assistant_client, auth_header):
|
|||||||
devices = body['payload']['devices']
|
devices = body['payload']['devices']
|
||||||
assert len(devices) == 3
|
assert len(devices) == 3
|
||||||
assert devices['climate.heatpump'] == {
|
assert devices['climate.heatpump'] == {
|
||||||
'on': True,
|
|
||||||
'online': True,
|
'online': True,
|
||||||
'thermostatTemperatureSetpoint': 20.0,
|
'thermostatTemperatureSetpoint': 20.0,
|
||||||
'thermostatTemperatureAmbient': 25.0,
|
'thermostatTemperatureAmbient': 25.0,
|
||||||
@ -262,7 +261,6 @@ def test_query_climate_request_f(hass_fixture, assistant_client, auth_header):
|
|||||||
devices = body['payload']['devices']
|
devices = body['payload']['devices']
|
||||||
assert len(devices) == 3
|
assert len(devices) == 3
|
||||||
assert devices['climate.heatpump'] == {
|
assert devices['climate.heatpump'] == {
|
||||||
'on': True,
|
|
||||||
'online': True,
|
'online': True,
|
||||||
'thermostatTemperatureSetpoint': -6.7,
|
'thermostatTemperatureSetpoint': -6.7,
|
||||||
'thermostatTemperatureAmbient': -3.9,
|
'thermostatTemperatureAmbient': -3.9,
|
||||||
|
@ -408,44 +408,9 @@ async def test_onoff_media_player(hass):
|
|||||||
|
|
||||||
|
|
||||||
async def test_onoff_climate(hass):
|
async def test_onoff_climate(hass):
|
||||||
"""Test OnOff trait support for climate domain."""
|
"""Test OnOff trait not supported for climate domain."""
|
||||||
assert trait.OnOffTrait.supported(climate.DOMAIN, climate.SUPPORT_ON_OFF)
|
assert not trait.OnOffTrait.supported(
|
||||||
|
climate.DOMAIN, climate.SUPPORT_ON_OFF)
|
||||||
trt_on = trait.OnOffTrait(hass, State('climate.bla', STATE_ON),
|
|
||||||
BASIC_CONFIG)
|
|
||||||
|
|
||||||
assert trt_on.sync_attributes() == {}
|
|
||||||
|
|
||||||
assert trt_on.query_attributes() == {
|
|
||||||
'on': True
|
|
||||||
}
|
|
||||||
|
|
||||||
trt_off = trait.OnOffTrait(hass, State('climate.bla', STATE_OFF),
|
|
||||||
BASIC_CONFIG)
|
|
||||||
|
|
||||||
assert trt_off.query_attributes() == {
|
|
||||||
'on': False
|
|
||||||
}
|
|
||||||
|
|
||||||
on_calls = async_mock_service(hass, climate.DOMAIN, SERVICE_TURN_ON)
|
|
||||||
await trt_on.execute(
|
|
||||||
trait.COMMAND_ONOFF, BASIC_DATA,
|
|
||||||
{'on': True})
|
|
||||||
assert len(on_calls) == 1
|
|
||||||
assert on_calls[0].data == {
|
|
||||||
ATTR_ENTITY_ID: 'climate.bla',
|
|
||||||
}
|
|
||||||
|
|
||||||
off_calls = async_mock_service(hass, climate.DOMAIN,
|
|
||||||
SERVICE_TURN_OFF)
|
|
||||||
|
|
||||||
await trt_on.execute(
|
|
||||||
trait.COMMAND_ONOFF, BASIC_DATA,
|
|
||||||
{'on': False})
|
|
||||||
assert len(off_calls) == 1
|
|
||||||
assert off_calls[0].data == {
|
|
||||||
ATTR_ENTITY_ID: 'climate.bla',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_dock_vacuum(hass):
|
async def test_dock_vacuum(hass):
|
||||||
@ -673,6 +638,48 @@ async def test_scene_script(hass):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_temperature_setting_climate_onoff(hass):
|
||||||
|
"""Test TemperatureSetting trait support for climate domain - range."""
|
||||||
|
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0)
|
||||||
|
assert trait.TemperatureSettingTrait.supported(
|
||||||
|
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE)
|
||||||
|
|
||||||
|
hass.config.units.temperature_unit = TEMP_FAHRENHEIT
|
||||||
|
|
||||||
|
trt = trait.TemperatureSettingTrait(hass, State(
|
||||||
|
'climate.bla', climate.STATE_AUTO, {
|
||||||
|
ATTR_SUPPORTED_FEATURES: (
|
||||||
|
climate.SUPPORT_OPERATION_MODE | climate.SUPPORT_ON_OFF),
|
||||||
|
climate.ATTR_OPERATION_MODE: climate.STATE_COOL,
|
||||||
|
climate.ATTR_OPERATION_LIST: [
|
||||||
|
climate.STATE_COOL,
|
||||||
|
climate.STATE_HEAT,
|
||||||
|
climate.STATE_AUTO,
|
||||||
|
],
|
||||||
|
climate.ATTR_MIN_TEMP: None,
|
||||||
|
climate.ATTR_MAX_TEMP: None,
|
||||||
|
}), BASIC_CONFIG)
|
||||||
|
assert trt.sync_attributes() == {
|
||||||
|
'availableThermostatModes': 'off,on,cool,heat,heatcool',
|
||||||
|
'thermostatTemperatureUnit': 'F',
|
||||||
|
}
|
||||||
|
assert trt.can_execute(trait.COMMAND_THERMOSTAT_SET_MODE, {})
|
||||||
|
|
||||||
|
calls = async_mock_service(
|
||||||
|
hass, climate.DOMAIN, SERVICE_TURN_ON)
|
||||||
|
await trt.execute(trait.COMMAND_THERMOSTAT_SET_MODE, BASIC_DATA, {
|
||||||
|
'thermostatMode': 'on',
|
||||||
|
})
|
||||||
|
assert len(calls) == 1
|
||||||
|
|
||||||
|
calls = async_mock_service(
|
||||||
|
hass, climate.DOMAIN, SERVICE_TURN_OFF)
|
||||||
|
await trt.execute(trait.COMMAND_THERMOSTAT_SET_MODE, BASIC_DATA, {
|
||||||
|
'thermostatMode': 'off',
|
||||||
|
})
|
||||||
|
assert len(calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_temperature_setting_climate_range(hass):
|
async def test_temperature_setting_climate_range(hass):
|
||||||
"""Test TemperatureSetting trait support for climate domain - range."""
|
"""Test TemperatureSetting trait support for climate domain - range."""
|
||||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0)
|
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0)
|
||||||
@ -685,6 +692,7 @@ async def test_temperature_setting_climate_range(hass):
|
|||||||
'climate.bla', climate.STATE_AUTO, {
|
'climate.bla', climate.STATE_AUTO, {
|
||||||
climate.ATTR_CURRENT_TEMPERATURE: 70,
|
climate.ATTR_CURRENT_TEMPERATURE: 70,
|
||||||
climate.ATTR_CURRENT_HUMIDITY: 25,
|
climate.ATTR_CURRENT_HUMIDITY: 25,
|
||||||
|
ATTR_SUPPORTED_FEATURES: climate.SUPPORT_OPERATION_MODE,
|
||||||
climate.ATTR_OPERATION_MODE: climate.STATE_AUTO,
|
climate.ATTR_OPERATION_MODE: climate.STATE_AUTO,
|
||||||
climate.ATTR_OPERATION_LIST: [
|
climate.ATTR_OPERATION_LIST: [
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
@ -755,6 +763,8 @@ async def test_temperature_setting_climate_setpoint(hass):
|
|||||||
|
|
||||||
trt = trait.TemperatureSettingTrait(hass, State(
|
trt = trait.TemperatureSettingTrait(hass, State(
|
||||||
'climate.bla', climate.STATE_AUTO, {
|
'climate.bla', climate.STATE_AUTO, {
|
||||||
|
ATTR_SUPPORTED_FEATURES: (
|
||||||
|
climate.SUPPORT_OPERATION_MODE | climate.SUPPORT_ON_OFF),
|
||||||
climate.ATTR_OPERATION_MODE: climate.STATE_COOL,
|
climate.ATTR_OPERATION_MODE: climate.STATE_COOL,
|
||||||
climate.ATTR_OPERATION_LIST: [
|
climate.ATTR_OPERATION_LIST: [
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
@ -766,7 +776,7 @@ async def test_temperature_setting_climate_setpoint(hass):
|
|||||||
climate.ATTR_CURRENT_TEMPERATURE: 20
|
climate.ATTR_CURRENT_TEMPERATURE: 20
|
||||||
}), BASIC_CONFIG)
|
}), BASIC_CONFIG)
|
||||||
assert trt.sync_attributes() == {
|
assert trt.sync_attributes() == {
|
||||||
'availableThermostatModes': 'off,cool',
|
'availableThermostatModes': 'off,on,cool',
|
||||||
'thermostatTemperatureUnit': 'C',
|
'thermostatTemperatureUnit': 'C',
|
||||||
}
|
}
|
||||||
assert trt.query_attributes() == {
|
assert trt.query_attributes() == {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user