Alexa temperature adjustment handle multiple setpoint (#95821)
* Alexa temperature adjustment handle multiple setpoint In "auto" mode with many thermostats, the thermostats expose both an upper and lower setpoint representing a range of temperatures. When a temperature delta is sent from Alexa (e.g. "lower by 2 degrees), we need to handle the case where the temperature property is not set, but instead the upper and lower setpoint properties are set. In this case, we adjust those properties via service call instead of the singular value. * Updating tests to fix coveragepull/96791/head^2
parent
564e618d0c
commit
44aa531a51
|
@ -857,14 +857,55 @@ async def async_api_adjust_target_temp(
|
|||
temp_delta = temperature_from_object(
|
||||
hass, directive.payload["targetSetpointDelta"], interval=True
|
||||
)
|
||||
target_temp = float(entity.attributes.get(ATTR_TEMPERATURE)) + temp_delta
|
||||
|
||||
if target_temp < min_temp or target_temp > max_temp:
|
||||
raise AlexaTempRangeError(hass, target_temp, min_temp, max_temp)
|
||||
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id, ATTR_TEMPERATURE: target_temp}
|
||||
|
||||
response = directive.response()
|
||||
|
||||
current_target_temp_high = entity.attributes.get(climate.ATTR_TARGET_TEMP_HIGH)
|
||||
current_target_temp_low = entity.attributes.get(climate.ATTR_TARGET_TEMP_LOW)
|
||||
if current_target_temp_high and current_target_temp_low:
|
||||
target_temp_high = float(current_target_temp_high) + temp_delta
|
||||
if target_temp_high < min_temp or target_temp_high > max_temp:
|
||||
raise AlexaTempRangeError(hass, target_temp_high, min_temp, max_temp)
|
||||
|
||||
target_temp_low = float(current_target_temp_low) + temp_delta
|
||||
if target_temp_low < min_temp or target_temp_low > max_temp:
|
||||
raise AlexaTempRangeError(hass, target_temp_low, min_temp, max_temp)
|
||||
|
||||
data = {
|
||||
ATTR_ENTITY_ID: entity.entity_id,
|
||||
climate.ATTR_TARGET_TEMP_HIGH: target_temp_high,
|
||||
climate.ATTR_TARGET_TEMP_LOW: target_temp_low,
|
||||
}
|
||||
|
||||
response.add_context_property(
|
||||
{
|
||||
"name": "upperSetpoint",
|
||||
"namespace": "Alexa.ThermostatController",
|
||||
"value": {"value": target_temp_high, "scale": API_TEMP_UNITS[unit]},
|
||||
}
|
||||
)
|
||||
response.add_context_property(
|
||||
{
|
||||
"name": "lowerSetpoint",
|
||||
"namespace": "Alexa.ThermostatController",
|
||||
"value": {"value": target_temp_low, "scale": API_TEMP_UNITS[unit]},
|
||||
}
|
||||
)
|
||||
else:
|
||||
target_temp = float(entity.attributes.get(ATTR_TEMPERATURE)) + temp_delta
|
||||
|
||||
if target_temp < min_temp or target_temp > max_temp:
|
||||
raise AlexaTempRangeError(hass, target_temp, min_temp, max_temp)
|
||||
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id, ATTR_TEMPERATURE: target_temp}
|
||||
response.add_context_property(
|
||||
{
|
||||
"name": "targetSetpoint",
|
||||
"namespace": "Alexa.ThermostatController",
|
||||
"value": {"value": target_temp, "scale": API_TEMP_UNITS[unit]},
|
||||
}
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain,
|
||||
climate.SERVICE_SET_TEMPERATURE,
|
||||
|
@ -872,13 +913,6 @@ async def async_api_adjust_target_temp(
|
|||
blocking=False,
|
||||
context=context,
|
||||
)
|
||||
response.add_context_property(
|
||||
{
|
||||
"name": "targetSetpoint",
|
||||
"namespace": "Alexa.ThermostatController",
|
||||
"value": {"value": target_temp, "scale": API_TEMP_UNITS[unit]},
|
||||
}
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
|
|
@ -2176,8 +2176,8 @@ async def test_thermostat(hass: HomeAssistant) -> None:
|
|||
"cool",
|
||||
{
|
||||
"temperature": 70.0,
|
||||
"target_temp_high": 80.0,
|
||||
"target_temp_low": 60.0,
|
||||
"target_temp_high": None,
|
||||
"target_temp_low": None,
|
||||
"current_temperature": 75.0,
|
||||
"friendly_name": "Test Thermostat",
|
||||
"supported_features": 1 | 2 | 4 | 128,
|
||||
|
@ -2439,6 +2439,103 @@ async def test_thermostat(hass: HomeAssistant) -> None:
|
|||
assert call.data["preset_mode"] == "eco"
|
||||
|
||||
|
||||
async def test_thermostat_dual(hass: HomeAssistant) -> None:
|
||||
"""Test thermostat discovery with auto mode, with upper and lower target temperatures."""
|
||||
hass.config.units = US_CUSTOMARY_SYSTEM
|
||||
device = (
|
||||
"climate.test_thermostat",
|
||||
"auto",
|
||||
{
|
||||
"temperature": None,
|
||||
"target_temp_high": 80.0,
|
||||
"target_temp_low": 60.0,
|
||||
"current_temperature": 75.0,
|
||||
"friendly_name": "Test Thermostat",
|
||||
"supported_features": 1 | 2 | 4 | 128,
|
||||
"hvac_modes": ["off", "heat", "cool", "auto", "dry", "fan_only"],
|
||||
"preset_mode": None,
|
||||
"preset_modes": ["eco"],
|
||||
"min_temp": 50,
|
||||
"max_temp": 90,
|
||||
},
|
||||
)
|
||||
appliance = await discovery_test(device, hass)
|
||||
|
||||
assert appliance["endpointId"] == "climate#test_thermostat"
|
||||
assert appliance["displayCategories"][0] == "THERMOSTAT"
|
||||
assert appliance["friendlyName"] == "Test Thermostat"
|
||||
|
||||
assert_endpoint_capabilities(
|
||||
appliance,
|
||||
"Alexa.PowerController",
|
||||
"Alexa.ThermostatController",
|
||||
"Alexa.TemperatureSensor",
|
||||
"Alexa.EndpointHealth",
|
||||
"Alexa",
|
||||
)
|
||||
|
||||
properties = await reported_properties(hass, "climate#test_thermostat")
|
||||
properties.assert_equal("Alexa.ThermostatController", "thermostatMode", "AUTO")
|
||||
properties.assert_equal(
|
||||
"Alexa.ThermostatController",
|
||||
"upperSetpoint",
|
||||
{"value": 80.0, "scale": "FAHRENHEIT"},
|
||||
)
|
||||
properties.assert_equal(
|
||||
"Alexa.ThermostatController",
|
||||
"lowerSetpoint",
|
||||
{"value": 60.0, "scale": "FAHRENHEIT"},
|
||||
)
|
||||
properties.assert_equal(
|
||||
"Alexa.TemperatureSensor", "temperature", {"value": 75.0, "scale": "FAHRENHEIT"}
|
||||
)
|
||||
|
||||
# Adjust temperature when in auto mode
|
||||
call, msg = await assert_request_calls_service(
|
||||
"Alexa.ThermostatController",
|
||||
"AdjustTargetTemperature",
|
||||
"climate#test_thermostat",
|
||||
"climate.set_temperature",
|
||||
hass,
|
||||
payload={"targetSetpointDelta": {"value": -5.0, "scale": "KELVIN"}},
|
||||
)
|
||||
assert call.data["target_temp_high"] == 71.0
|
||||
assert call.data["target_temp_low"] == 51.0
|
||||
properties = ReportedProperties(msg["context"]["properties"])
|
||||
properties.assert_equal(
|
||||
"Alexa.ThermostatController",
|
||||
"upperSetpoint",
|
||||
{"value": 71.0, "scale": "FAHRENHEIT"},
|
||||
)
|
||||
properties.assert_equal(
|
||||
"Alexa.ThermostatController",
|
||||
"lowerSetpoint",
|
||||
{"value": 51.0, "scale": "FAHRENHEIT"},
|
||||
)
|
||||
|
||||
# Fails if the upper setpoint goes too high
|
||||
msg = await assert_request_fails(
|
||||
"Alexa.ThermostatController",
|
||||
"AdjustTargetTemperature",
|
||||
"climate#test_thermostat",
|
||||
"climate.set_temperature",
|
||||
hass,
|
||||
payload={"targetSetpointDelta": {"value": 6.0, "scale": "CELSIUS"}},
|
||||
)
|
||||
assert msg["event"]["payload"]["type"] == "TEMPERATURE_VALUE_OUT_OF_RANGE"
|
||||
|
||||
# Fails if the lower setpoint goes too low
|
||||
msg = await assert_request_fails(
|
||||
"Alexa.ThermostatController",
|
||||
"AdjustTargetTemperature",
|
||||
"climate#test_thermostat",
|
||||
"climate.set_temperature",
|
||||
hass,
|
||||
payload={"targetSetpointDelta": {"value": -6.0, "scale": "CELSIUS"}},
|
||||
)
|
||||
assert msg["event"]["payload"]["type"] == "TEMPERATURE_VALUE_OUT_OF_RANGE"
|
||||
|
||||
|
||||
async def test_exclude_filters(hass: HomeAssistant) -> None:
|
||||
"""Test exclusion filters."""
|
||||
request = get_new_request("Alexa.Discovery", "Discover")
|
||||
|
|
Loading…
Reference in New Issue