diff --git a/homeassistant/components/alexa/errors.py b/homeassistant/components/alexa/errors.py index 2c5ced62403..f8e3720e160 100644 --- a/homeassistant/components/alexa/errors.py +++ b/homeassistant/components/alexa/errors.py @@ -90,6 +90,13 @@ class AlexaUnsupportedThermostatModeError(AlexaError): error_type = "UNSUPPORTED_THERMOSTAT_MODE" +class AlexaUnsupportedThermostatTargetStateError(AlexaError): + """Class to represent unsupported climate target state error.""" + + namespace = "Alexa.ThermostatController" + error_type = "INVALID_TARGET_STATE" + + class AlexaTempRangeError(AlexaError): """Class to represent TempRange errors.""" diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index 3e995e9ffe2..f99b0231e4d 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -73,6 +73,7 @@ from .errors import ( AlexaSecurityPanelAuthorizationRequired, AlexaTempRangeError, AlexaUnsupportedThermostatModeError, + AlexaUnsupportedThermostatTargetStateError, AlexaVideoActionNotPermittedForContentError, ) from .state_report import AlexaDirective, AlexaResponse, async_enable_proactive_mode @@ -911,7 +912,13 @@ async def async_api_adjust_target_temp( } ) else: - target_temp = float(entity.attributes[ATTR_TEMPERATURE]) + temp_delta + current_target_temp: str | None = entity.attributes.get(ATTR_TEMPERATURE) + if current_target_temp is None: + raise AlexaUnsupportedThermostatTargetStateError( + "The current target temperature is not set, " + "cannot adjust target temperature" + ) + target_temp = float(current_target_temp) + temp_delta if target_temp < min_temp or target_temp > max_temp: raise AlexaTempRangeError(hass, target_temp, min_temp, max_temp) diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index c42ea0a0f6a..bbdf3efeb5f 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -2471,6 +2471,75 @@ async def test_thermostat(hass: HomeAssistant) -> None: assert call.data["preset_mode"] == "eco" +async def test_no_current_target_temp_adjusting_temp(hass: HomeAssistant) -> None: + """Test thermostat adjusting temp with no initial target temperature.""" + hass.config.units = US_CUSTOMARY_SYSTEM + device = ( + "climate.test_thermostat", + "cool", + { + "temperature": None, + "target_temp_high": None, + "target_temp_low": None, + "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" + + capabilities = 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", "COOL") + properties.assert_not_has_property( + "Alexa.ThermostatController", + "targetSetpoint", + ) + properties.assert_equal( + "Alexa.TemperatureSensor", "temperature", {"value": 75.0, "scale": "FAHRENHEIT"} + ) + + thermostat_capability = get_capability(capabilities, "Alexa.ThermostatController") + assert thermostat_capability is not None + configuration = thermostat_capability["configuration"] + assert configuration["supportsScheduling"] is False + + supported_modes = ["OFF", "HEAT", "COOL", "AUTO", "ECO", "CUSTOM"] + for mode in supported_modes: + assert mode in configuration["supportedModes"] + + # Adjust temperature where target temp is not set + msg = await assert_request_fails( + "Alexa.ThermostatController", + "AdjustTargetTemperature", + "climate#test_thermostat", + "climate.set_temperature", + hass, + payload={"targetSetpointDelta": {"value": -5.0, "scale": "KELVIN"}}, + ) + assert msg["event"]["payload"]["type"] == "INVALID_TARGET_STATE" + assert msg["event"]["payload"]["message"] == ( + "The current target temperature is not set, cannot adjust target temperature" + ) + + 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