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 coverage
pull/96791/head^2
Mike Keesey 2023-07-17 17:12:15 -06:00 committed by GitHub
parent 564e618d0c
commit 44aa531a51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 146 additions and 15 deletions

View File

@ -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

View File

@ -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")