diff --git a/homeassistant/components/nest/climate.py b/homeassistant/components/nest/climate.py index 02874cab84c..0dcdec1cac1 100644 --- a/homeassistant/components/nest/climate.py +++ b/homeassistant/components/nest/climate.py @@ -75,6 +75,7 @@ FAN_INV_MODES = list(FAN_INV_MODE_MAP) MAX_FAN_DURATION = 43200 # 15 hours is the max in the SDM API MIN_TEMP = 10 MAX_TEMP = 32 +MIN_TEMP_RANGE = 1.66667 async def async_setup_entry( @@ -313,6 +314,13 @@ class ThermostatEntity(ClimateEntity): try: if self.preset_mode == PRESET_ECO or hvac_mode == HVACMode.HEAT_COOL: if low_temp and high_temp: + if high_temp - low_temp < MIN_TEMP_RANGE: + # Ensure there is a minimum gap from the new temp. Pick + # the temp that is not changing as the one to move. + if abs(high_temp - self.target_temperature_high) < 0.01: + high_temp = low_temp + MIN_TEMP_RANGE + else: + low_temp = high_temp - MIN_TEMP_RANGE await trait.set_range(low_temp, high_temp) elif hvac_mode == HVACMode.COOL and temp: await trait.set_cool(temp) diff --git a/tests/components/nest/test_climate.py b/tests/components/nest/test_climate.py index 037894b43f5..c920eb5717d 100644 --- a/tests/components/nest/test_climate.py +++ b/tests/components/nest/test_climate.py @@ -758,6 +758,75 @@ async def test_thermostat_set_temperature_hvac_mode( } +@pytest.mark.parametrize( + ("setpoint", "target_low", "target_high", "expected_params"), + [ + ( + { + "heatCelsius": 19.0, + "coolCelsius": 25.0, + }, + 19.0, + 20.0, + # Cool is accepted and lowers heat by the min range + {"heatCelsius": 18.33333, "coolCelsius": 20.0}, + ), + ( + { + "heatCelsius": 19.0, + "coolCelsius": 25.0, + }, + 24.0, + 25.0, + # Cool is accepted and lowers heat by the min range + {"heatCelsius": 24.0, "coolCelsius": 25.66667}, + ), + ], +) +async def test_thermostat_set_temperature_range_too_close( + hass: HomeAssistant, + setup_platform: PlatformSetup, + auth: FakeAuth, + create_device: CreateDevice, + setpoint: dict[str, Any], + target_low: float, + target_high: float, + expected_params: dict[str, Any], +) -> None: + """Test setting an HVAC temperature range that is too small of a range.""" + create_device.create( + { + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "HEATCOOL", + }, + "sdm.devices.traits.ThermostatTemperatureSetpoint": setpoint, + }, + ) + await setup_platform() + + assert len(hass.states.async_all()) == 1 + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert thermostat.state == HVACMode.HEAT_COOL + + # Move the target temp to be in too small of a range + await common.async_set_temperature( + hass, + target_temp_low=target_low, + target_temp_high=target_high, + ) + await hass.async_block_till_done() + + assert auth.method == "post" + assert auth.url == DEVICE_COMMAND + assert auth.json == { + "command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetRange", + "params": expected_params, + } + + async def test_thermostat_set_heat_cool( hass: HomeAssistant, setup_platform: PlatformSetup,