diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index eb23b09627e..c1b99b017e5 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -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 diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index a1f77a9b49b..a2dcdedd470 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -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")