From a913587eb6dff0d5c9a5846d4067ef6974d3e405 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Wed, 31 Jul 2024 19:17:53 +0200 Subject: [PATCH] Climate validate temperature(s) out of range (#118649) * Climate temperature out of range * Fix test sensibo * use temp converting for min/max * Fix * Fix mqtt tests * Fix honeywell tests * Fix Balboa tests * Fix whirlpool test * Fix teslemetry test * Fix plugwise test * Fix tplink test * Fix generic thermostat test * Fix modbus test * Fix fritzbox tests * Honewell --- homeassistant/components/climate/__init__.py | 29 +++- homeassistant/components/climate/strings.json | 3 + homeassistant/components/honeywell/climate.py | 9 +- tests/components/balboa/test_climate.py | 2 + tests/components/climate/test_init.py | 138 +++++++++++++++++- tests/components/fritzbox/test_climate.py | 8 +- .../generic_thermostat/test_climate.py | 4 +- tests/components/honeywell/conftest.py | 1 + .../honeywell/snapshots/test_climate.ambr | 6 +- tests/components/honeywell/test_climate.py | 71 +++++---- tests/components/modbus/test_climate.py | 8 +- tests/components/mqtt/test_climate.py | 14 +- tests/components/plugwise/test_climate.py | 4 +- tests/components/sensibo/test_climate.py | 6 +- tests/components/teslemetry/test_climate.py | 2 +- tests/components/tplink/test_climate.py | 5 +- tests/components/whirlpool/test_climate.py | 4 +- 17 files changed, 245 insertions(+), 69 deletions(-) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 94cba54b247..f546ae0e671 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -914,12 +914,37 @@ async def async_service_temperature_set( """Handle set temperature service.""" hass = entity.hass kwargs = {} + min_temp = entity.min_temp + max_temp = entity.max_temp + temp_unit = entity.temperature_unit for value, temp in service_call.data.items(): if value in CONVERTIBLE_ATTRIBUTE: - kwargs[value] = TemperatureConverter.convert( - temp, hass.config.units.temperature_unit, entity.temperature_unit + kwargs[value] = check_temp = TemperatureConverter.convert( + temp, hass.config.units.temperature_unit, temp_unit ) + + _LOGGER.debug( + "Check valid temperature %d %s (%d %s) in range %d %s - %d %s", + check_temp, + entity.temperature_unit, + temp, + hass.config.units.temperature_unit, + min_temp, + temp_unit, + max_temp, + temp_unit, + ) + if check_temp < min_temp or check_temp > max_temp: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="temp_out_of_range", + translation_placeholders={ + "check_temp": str(check_temp), + "min_temp": str(min_temp), + "max_temp": str(max_temp), + }, + ) else: kwargs[value] = temp diff --git a/homeassistant/components/climate/strings.json b/homeassistant/components/climate/strings.json index dc212441824..1af21815b9f 100644 --- a/homeassistant/components/climate/strings.json +++ b/homeassistant/components/climate/strings.json @@ -266,6 +266,9 @@ }, "not_valid_fan_mode": { "message": "Fan mode {mode} is not valid. Valid fan modes are: {modes}." + }, + "temp_out_of_range": { + "message": "Provided temperature {check_temp} is not valid. Accepted range is {min_temp} to {max_temp}." } } } diff --git a/homeassistant/components/honeywell/climate.py b/homeassistant/components/honeywell/climate.py index d9260fc3be5..141cb87f117 100644 --- a/homeassistant/components/honeywell/climate.py +++ b/homeassistant/components/honeywell/climate.py @@ -42,6 +42,7 @@ from homeassistant.helpers import ( ) from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.util.unit_conversion import TemperatureConverter from . import HoneywellData from .const import ( @@ -259,7 +260,9 @@ class HoneywellUSThermostat(ClimateEntity): self._device.raw_ui_data["HeatLowerSetptLimit"], ] ) - return DEFAULT_MIN_TEMP + return TemperatureConverter.convert( + DEFAULT_MIN_TEMP, UnitOfTemperature.CELSIUS, self.temperature_unit + ) @property def max_temp(self) -> float: @@ -275,7 +278,9 @@ class HoneywellUSThermostat(ClimateEntity): self._device.raw_ui_data["HeatUpperSetptLimit"], ] ) - return DEFAULT_MAX_TEMP + return TemperatureConverter.convert( + DEFAULT_MAX_TEMP, UnitOfTemperature.CELSIUS, self.temperature_unit + ) @property def current_humidity(self) -> int | None: diff --git a/tests/components/balboa/test_climate.py b/tests/components/balboa/test_climate.py index c877f2858cd..850184a7d71 100644 --- a/tests/components/balboa/test_climate.py +++ b/tests/components/balboa/test_climate.py @@ -85,6 +85,8 @@ async def test_spa_temperature( hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry ) -> None: """Test spa temperature settings.""" + client.temperature_minimum = 110 + client.temperature_maximum = 250 # flip the spa into F # set temp to a valid number state = await _patch_spa_settemp(hass, client, 0, 100) diff --git a/tests/components/climate/test_init.py b/tests/components/climate/test_init.py index ced75ff7ef7..f306551e540 100644 --- a/tests/components/climate/test_init.py +++ b/tests/components/climate/test_init.py @@ -4,6 +4,7 @@ from __future__ import annotations from enum import Enum from types import ModuleType +from typing import Any from unittest.mock import MagicMock, Mock, patch import pytest @@ -17,9 +18,14 @@ from homeassistant.components.climate import ( HVACMode, ) from homeassistant.components.climate.const import ( + ATTR_CURRENT_TEMPERATURE, ATTR_FAN_MODE, + ATTR_MAX_TEMP, + ATTR_MIN_TEMP, ATTR_PRESET_MODE, ATTR_SWING_MODE, + ATTR_TARGET_TEMP_HIGH, + ATTR_TARGET_TEMP_LOW, SERVICE_SET_FAN_MODE, SERVICE_SET_PRESET_MODE, SERVICE_SET_SWING_MODE, @@ -27,7 +33,13 @@ from homeassistant.components.climate.const import ( ClimateEntityFeature, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, UnitOfTemperature +from homeassistant.const import ( + ATTR_TEMPERATURE, + PRECISION_WHOLE, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + UnitOfTemperature, +) from homeassistant.core import HomeAssistant from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers import issue_registry as ir @@ -1152,3 +1164,127 @@ async def test_no_issue_no_aux_property( "the auxiliary heater methods in a subclass of ClimateEntity which is deprecated " "and will be unsupported from Home Assistant 2024.10." ) not in caplog.text + + +async def test_temperature_validation( + hass: HomeAssistant, config_flow_fixture: None +) -> None: + """Test validation for temperatures.""" + + class MockClimateEntityTemp(MockClimateEntity): + """Mock climate class with mocked aux heater.""" + + _attr_supported_features = ( + ClimateEntityFeature.FAN_MODE + | ClimateEntityFeature.PRESET_MODE + | ClimateEntityFeature.SWING_MODE + | ClimateEntityFeature.TARGET_TEMPERATURE + | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE + ) + _attr_target_temperature = 15 + _attr_target_temperature_high = 18 + _attr_target_temperature_low = 10 + _attr_target_temperature_step = PRECISION_WHOLE + + def set_temperature(self, **kwargs: Any) -> None: + """Set new target temperature.""" + if ATTR_TEMPERATURE in kwargs: + self._attr_target_temperature = kwargs[ATTR_TEMPERATURE] + if ATTR_TARGET_TEMP_HIGH in kwargs: + self._attr_target_temperature_high = kwargs[ATTR_TARGET_TEMP_HIGH] + self._attr_target_temperature_low = kwargs[ATTR_TARGET_TEMP_LOW] + + async def async_setup_entry_init( + hass: HomeAssistant, config_entry: ConfigEntry + ) -> bool: + """Set up test config entry.""" + await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN]) + return True + + async def async_setup_entry_climate_platform( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, + ) -> None: + """Set up test climate platform via config entry.""" + async_add_entities( + [MockClimateEntityTemp(name="test", entity_id="climate.test")] + ) + + mock_integration( + hass, + MockModule( + "test", + async_setup_entry=async_setup_entry_init, + ), + built_in=False, + ) + mock_platform( + hass, + "test.climate", + MockPlatform(async_setup_entry=async_setup_entry_climate_platform), + ) + + config_entry = MockConfigEntry(domain="test") + config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get("climate.test") + assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) is None + assert state.attributes.get(ATTR_MIN_TEMP) == 7 + assert state.attributes.get(ATTR_MAX_TEMP) == 35 + + with pytest.raises( + ServiceValidationError, + match="Provided temperature 40.0 is not valid. Accepted range is 7 to 35", + ) as exc: + await hass.services.async_call( + DOMAIN, + SERVICE_SET_TEMPERATURE, + { + "entity_id": "climate.test", + ATTR_TEMPERATURE: "40", + }, + blocking=True, + ) + assert ( + str(exc.value) + == "Provided temperature 40.0 is not valid. Accepted range is 7 to 35" + ) + assert exc.value.translation_key == "temp_out_of_range" + + with pytest.raises( + ServiceValidationError, + match="Provided temperature 0.0 is not valid. Accepted range is 7 to 35", + ) as exc: + await hass.services.async_call( + DOMAIN, + SERVICE_SET_TEMPERATURE, + { + "entity_id": "climate.test", + ATTR_TARGET_TEMP_HIGH: "25", + ATTR_TARGET_TEMP_LOW: "0", + }, + blocking=True, + ) + assert ( + str(exc.value) + == "Provided temperature 0.0 is not valid. Accepted range is 7 to 35" + ) + assert exc.value.translation_key == "temp_out_of_range" + + await hass.services.async_call( + DOMAIN, + SERVICE_SET_TEMPERATURE, + { + "entity_id": "climate.test", + ATTR_TARGET_TEMP_HIGH: "25", + ATTR_TARGET_TEMP_LOW: "10", + }, + blocking=True, + ) + + state = hass.states.get("climate.test") + assert state.attributes.get(ATTR_TARGET_TEMP_LOW) == 10 + assert state.attributes.get(ATTR_TARGET_TEMP_HIGH) == 25 diff --git a/tests/components/fritzbox/test_climate.py b/tests/components/fritzbox/test_climate.py index 8d1da9d09d5..853c09c534b 100644 --- a/tests/components/fritzbox/test_climate.py +++ b/tests/components/fritzbox/test_climate.py @@ -263,10 +263,10 @@ async def test_set_temperature_temperature(hass: HomeAssistant, fritz: Mock) -> await hass.services.async_call( DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 123}, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 23}, True, ) - assert device.set_target_temperature.call_args_list == [call(123)] + assert device.set_target_temperature.call_args_list == [call(23)] async def test_set_temperature_mode_off(hass: HomeAssistant, fritz: Mock) -> None: @@ -282,7 +282,7 @@ async def test_set_temperature_mode_off(hass: HomeAssistant, fritz: Mock) -> Non { ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.OFF, - ATTR_TEMPERATURE: 123, + ATTR_TEMPERATURE: 23, }, True, ) @@ -303,7 +303,7 @@ async def test_set_temperature_mode_heat(hass: HomeAssistant, fritz: Mock) -> No { ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.HEAT, - ATTR_TEMPERATURE: 123, + ATTR_TEMPERATURE: 23, }, True, ) diff --git a/tests/components/generic_thermostat/test_climate.py b/tests/components/generic_thermostat/test_climate.py index 18e31b9591f..0f438056fbd 100644 --- a/tests/components/generic_thermostat/test_climate.py +++ b/tests/components/generic_thermostat/test_climate.py @@ -1097,9 +1097,9 @@ async def setup_comp_9(hass: HomeAssistant) -> None: async def test_precision(hass: HomeAssistant) -> None: """Test that setting precision to tenths works as intended.""" hass.config.units = US_CUSTOMARY_SYSTEM - await common.async_set_temperature(hass, 23.27) + await common.async_set_temperature(hass, 55.27) state = hass.states.get(ENTITY) - assert state.attributes.get("temperature") == 23.3 + assert state.attributes.get("temperature") == 55.3 # check that target_temp_step defaults to precision assert state.attributes.get("target_temp_step") == 0.1 diff --git a/tests/components/honeywell/conftest.py b/tests/components/honeywell/conftest.py index 5c5b6c0a44a..e48664db9ae 100644 --- a/tests/components/honeywell/conftest.py +++ b/tests/components/honeywell/conftest.py @@ -86,6 +86,7 @@ def device(): mock_device.system_mode = "off" mock_device.name = "device1" mock_device.current_temperature = CURRENTTEMPERATURE + mock_device.temperature_unit = "C" mock_device.mac_address = "macaddress1" mock_device.outdoor_temperature = None mock_device.outdoor_humidity = None diff --git a/tests/components/honeywell/snapshots/test_climate.ambr b/tests/components/honeywell/snapshots/test_climate.ambr index d1faf9af9a0..25bb73851c6 100644 --- a/tests/components/honeywell/snapshots/test_climate.ambr +++ b/tests/components/honeywell/snapshots/test_climate.ambr @@ -3,7 +3,7 @@ ReadOnlyDict({ 'aux_heat': 'off', 'current_humidity': 50, - 'current_temperature': -6.7, + 'current_temperature': 20, 'fan_action': 'idle', 'fan_mode': 'auto', 'fan_modes': list([ @@ -20,9 +20,9 @@ , ]), 'max_humidity': 99, - 'max_temp': 1.7, + 'max_temp': 35, 'min_humidity': 30, - 'min_temp': -13.9, + 'min_temp': 7, 'permanent_hold': False, 'preset_mode': 'none', 'preset_modes': list([ diff --git a/tests/components/honeywell/test_climate.py b/tests/components/honeywell/test_climate.py index b57be5f1838..55a55f7d7e7 100644 --- a/tests/components/honeywell/test_climate.py +++ b/tests/components/honeywell/test_climate.py @@ -92,14 +92,13 @@ async def test_dynamic_attributes( hass: HomeAssistant, device: MagicMock, config_entry: MagicMock ) -> None: """Test dynamic attributes.""" - await init_integration(hass, config_entry) entity_id = f"climate.{device.name}" state = hass.states.get(entity_id) assert state.state == HVACMode.OFF attributes = state.attributes - assert attributes["current_temperature"] == -6.7 + assert attributes["current_temperature"] == 20 assert attributes["current_humidity"] == 50 device.system_mode = "cool" @@ -114,7 +113,7 @@ async def test_dynamic_attributes( state = hass.states.get(entity_id) assert state.state == HVACMode.COOL attributes = state.attributes - assert attributes["current_temperature"] == -6.1 + assert attributes["current_temperature"] == 21 assert attributes["current_humidity"] == 55 device.system_mode = "heat" @@ -129,7 +128,7 @@ async def test_dynamic_attributes( state = hass.states.get(entity_id) assert state.state == HVACMode.HEAT attributes = state.attributes - assert attributes["current_temperature"] == 16.1 + assert attributes["current_temperature"] == 61 assert attributes["current_humidity"] == 50 device.system_mode = "auto" @@ -142,7 +141,7 @@ async def test_dynamic_attributes( state = hass.states.get(entity_id) assert state.state == HVACMode.HEAT_COOL attributes = state.attributes - assert attributes["current_temperature"] == 16.1 + assert attributes["current_temperature"] == 61 assert attributes["current_humidity"] == 50 @@ -348,7 +347,7 @@ async def test_service_calls_off_mode( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 35}, blocking=True, ) @@ -362,8 +361,8 @@ async def test_service_calls_off_mode( }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(35) + device.set_setpoint_heat.assert_called_with(25) device.set_setpoint_heat.reset_mock() device.set_setpoint_heat.side_effect = aiosomecomfort.SomeComfortError @@ -375,13 +374,13 @@ async def test_service_calls_off_mode( SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: entity_id, - ATTR_TARGET_TEMP_LOW: 25.0, - ATTR_TARGET_TEMP_HIGH: 35.0, + ATTR_TARGET_TEMP_LOW: 24.0, + ATTR_TARGET_TEMP_HIGH: 34.0, }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(34) + device.set_setpoint_heat.assert_called_with(24) assert "Invalid temperature" in caplog.text device.set_setpoint_heat.reset_mock() @@ -399,14 +398,14 @@ async def test_service_calls_off_mode( }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(35) + device.set_setpoint_heat.assert_called_with(25) reset_mock(device) await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 35}, blocking=True, ) device.set_setpoint_heat.assert_not_called() @@ -517,7 +516,7 @@ async def test_service_calls_cool_mode( {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, blocking=True, ) - device.set_hold_cool.assert_called_once_with(datetime.time(2, 30), 59) + device.set_hold_cool.assert_called_once_with(datetime.time(2, 30), 15) device.set_hold_cool.reset_mock() await hass.services.async_call( @@ -525,13 +524,13 @@ async def test_service_calls_cool_mode( SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: entity_id, - ATTR_TARGET_TEMP_LOW: 25.0, - ATTR_TARGET_TEMP_HIGH: 35.0, + ATTR_TARGET_TEMP_LOW: 15.0, + ATTR_TARGET_TEMP_HIGH: 20.0, }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(20) + device.set_setpoint_heat.assert_called_with(15) caplog.clear() device.set_setpoint_cool.reset_mock() @@ -543,13 +542,13 @@ async def test_service_calls_cool_mode( SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: entity_id, - ATTR_TARGET_TEMP_LOW: 25.0, - ATTR_TARGET_TEMP_HIGH: 35.0, + ATTR_TARGET_TEMP_LOW: 15.0, + ATTR_TARGET_TEMP_HIGH: 20.0, }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(20) + device.set_setpoint_heat.assert_called_with(15) assert "Invalid temperature" in caplog.text reset_mock(device) @@ -733,10 +732,10 @@ async def test_service_calls_heat_mode( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25}, blocking=True, ) - device.set_hold_heat.assert_called_once_with(datetime.time(2, 30), 59) + device.set_hold_heat.assert_called_once_with(datetime.time(2, 30), 25) device.set_hold_heat.reset_mock() device.set_hold_heat.side_effect = aiosomecomfort.SomeComfortError @@ -744,10 +743,10 @@ async def test_service_calls_heat_mode( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25}, blocking=True, ) - device.set_hold_heat.assert_called_once_with(datetime.time(2, 30), 59) + device.set_hold_heat.assert_called_once_with(datetime.time(2, 30), 25) device.set_hold_heat.reset_mock() assert "Invalid temperature" in caplog.text @@ -756,10 +755,10 @@ async def test_service_calls_heat_mode( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25}, blocking=True, ) - device.set_hold_heat.assert_called_once_with(datetime.time(2, 30), 59) + device.set_hold_heat.assert_called_once_with(datetime.time(2, 30), 25) device.set_hold_heat.reset_mock() caplog.clear() @@ -773,8 +772,8 @@ async def test_service_calls_heat_mode( }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(35) + device.set_setpoint_heat.assert_called_with(25) device.set_setpoint_heat.reset_mock() device.set_setpoint_heat.side_effect = aiosomecomfort.SomeComfortError @@ -789,8 +788,8 @@ async def test_service_calls_heat_mode( }, blocking=True, ) - device.set_setpoint_cool.assert_called_with(95) - device.set_setpoint_heat.assert_called_with(77) + device.set_setpoint_cool.assert_called_with(35) + device.set_setpoint_heat.assert_called_with(25) assert "Invalid temperature" in caplog.text reset_mock(device) @@ -984,8 +983,8 @@ async def test_service_calls_auto_mode( }, blocking=True, ) - device.set_setpoint_cool.assert_called_once_with(95) - device.set_setpoint_heat.assert_called_once_with(77) + device.set_setpoint_cool.assert_called_once_with(35) + device.set_setpoint_heat.assert_called_once_with(25) reset_mock(device) caplog.clear() diff --git a/tests/components/modbus/test_climate.py b/tests/components/modbus/test_climate.py index a52285b22d7..5578234ee6e 100644 --- a/tests/components/modbus/test_climate.py +++ b/tests/components/modbus/test_climate.py @@ -766,7 +766,7 @@ async def test_service_climate_swing_update( ("temperature", "result", "do_config"), [ ( - 35, + 31, [0x00], { CONF_CLIMATES: [ @@ -781,7 +781,7 @@ async def test_service_climate_swing_update( }, ), ( - 36, + 32, [0x00, 0x00], { CONF_CLIMATES: [ @@ -796,7 +796,7 @@ async def test_service_climate_swing_update( }, ), ( - 37.5, + 33.5, [0x00, 0x00], { CONF_CLIMATES: [ @@ -811,7 +811,7 @@ async def test_service_climate_swing_update( }, ), ( - "39", + "34", [0x00, 0x00, 0x00, 0x00], { CONF_CLIMATES: [ diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index f29c16f19ea..13bd6b5feda 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -654,11 +654,11 @@ async def test_set_target_temperature( assert state.state == "heat" mqtt_mock.async_publish.assert_called_once_with("mode-topic", "heat", 0, False) mqtt_mock.async_publish.reset_mock() - await common.async_set_temperature(hass, temperature=47, entity_id=ENTITY_CLIMATE) + await common.async_set_temperature(hass, temperature=35, entity_id=ENTITY_CLIMATE) state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("temperature") == 47 + assert state.attributes.get("temperature") == 35 mqtt_mock.async_publish.assert_called_once_with( - "temperature-topic", "47.0", 0, False + "temperature-topic", "35.0", 0, False ) # also test directly supplying the operation mode to set_temperature @@ -713,7 +713,7 @@ async def test_set_target_temperature_pessimistic( state = hass.states.get(ENTITY_CLIMATE) assert state.attributes.get("temperature") is None await common.async_set_hvac_mode(hass, "heat", ENTITY_CLIMATE) - await common.async_set_temperature(hass, temperature=47, entity_id=ENTITY_CLIMATE) + await common.async_set_temperature(hass, temperature=35, entity_id=ENTITY_CLIMATE) state = hass.states.get(ENTITY_CLIMATE) assert state.attributes.get("temperature") is None @@ -1590,13 +1590,13 @@ async def test_set_and_templates( assert state.attributes.get("swing_mode") == "on" # Temperature - await common.async_set_temperature(hass, temperature=47, entity_id=ENTITY_CLIMATE) + await common.async_set_temperature(hass, temperature=35, entity_id=ENTITY_CLIMATE) mqtt_mock.async_publish.assert_called_once_with( - "temperature-topic", "temp: 47.0", 0, False + "temperature-topic", "temp: 35.0", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("temperature") == 47 + assert state.attributes.get("temperature") == 35 # Temperature Low/High await common.async_set_temperature( diff --git a/tests/components/plugwise/test_climate.py b/tests/components/plugwise/test_climate.py index c91e4d37ba6..70cef16bcdc 100644 --- a/tests/components/plugwise/test_climate.py +++ b/tests/components/plugwise/test_climate.py @@ -14,7 +14,7 @@ from homeassistant.components.climate import ( HVACMode, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError +from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.util.dt import utcnow from tests.common import MockConfigEntry, async_fire_time_changed @@ -196,7 +196,7 @@ async def test_adam_climate_entity_climate_changes( "c50f167537524366a5af7aa3942feb1e", {"setpoint": 25.0} ) - with pytest.raises(ValueError): + with pytest.raises(ServiceValidationError): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, diff --git a/tests/components/sensibo/test_climate.py b/tests/components/sensibo/test_climate.py index 6b4aedab828..b5a7be7bde0 100644 --- a/tests/components/sensibo/test_climate.py +++ b/tests/components/sensibo/test_climate.py @@ -400,6 +400,10 @@ async def test_climate_temperatures( "homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", return_value={"result": {"status": "Success"}}, ), + pytest.raises( + ServiceValidationError, + match="Provided temperature 24.0 is not valid. Accepted range is 10 to 20", + ), ): await hass.services.async_call( CLIMATE_DOMAIN, @@ -410,7 +414,7 @@ async def test_climate_temperatures( await hass.async_block_till_done() state2 = hass.states.get("climate.hallway") - assert state2.attributes["temperature"] == 20 + assert state2.attributes["temperature"] == 19 with ( patch( diff --git a/tests/components/teslemetry/test_climate.py b/tests/components/teslemetry/test_climate.py index 250413396c1..31a39f1f21a 100644 --- a/tests/components/teslemetry/test_climate.py +++ b/tests/components/teslemetry/test_climate.py @@ -199,7 +199,7 @@ async def test_climate( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: [entity_id], ATTR_TEMPERATURE: 25}, + {ATTR_ENTITY_ID: [entity_id], ATTR_TEMPERATURE: 34}, blocking=True, ) diff --git a/tests/components/tplink/test_climate.py b/tests/components/tplink/test_climate.py index a80a74a5697..2f24fa829f9 100644 --- a/tests/components/tplink/test_climate.py +++ b/tests/components/tplink/test_climate.py @@ -120,12 +120,13 @@ async def test_set_temperature( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mocked_hub: Device ) -> None: """Test that set_temperature service calls the setter.""" + mocked_thermostat = mocked_hub.children[0] + mocked_thermostat.features["target_temperature"].minimum_value = 0 + await setup_platform_for_device( hass, mock_config_entry, Platform.CLIMATE, mocked_hub ) - mocked_thermostat = mocked_hub.children[0] - await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, diff --git a/tests/components/whirlpool/test_climate.py b/tests/components/whirlpool/test_climate.py index 18016bd9c67..cdae28f4432 100644 --- a/tests/components/whirlpool/test_climate.py +++ b/tests/components/whirlpool/test_climate.py @@ -264,10 +264,10 @@ async def test_service_calls( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 16}, blocking=True, ) - mock_instance.set_temp.assert_called_once_with(15) + mock_instance.set_temp.assert_called_once_with(16) mock_instance.set_mode.reset_mock() await hass.services.async_call(