mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
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
This commit is contained in:
parent
ae9e8ca419
commit
a913587eb6
@ -914,12 +914,37 @@ async def async_service_temperature_set(
|
|||||||
"""Handle set temperature service."""
|
"""Handle set temperature service."""
|
||||||
hass = entity.hass
|
hass = entity.hass
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
min_temp = entity.min_temp
|
||||||
|
max_temp = entity.max_temp
|
||||||
|
temp_unit = entity.temperature_unit
|
||||||
|
|
||||||
for value, temp in service_call.data.items():
|
for value, temp in service_call.data.items():
|
||||||
if value in CONVERTIBLE_ATTRIBUTE:
|
if value in CONVERTIBLE_ATTRIBUTE:
|
||||||
kwargs[value] = TemperatureConverter.convert(
|
kwargs[value] = check_temp = TemperatureConverter.convert(
|
||||||
temp, hass.config.units.temperature_unit, entity.temperature_unit
|
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:
|
else:
|
||||||
kwargs[value] = temp
|
kwargs[value] = temp
|
||||||
|
|
||||||
|
@ -266,6 +266,9 @@
|
|||||||
},
|
},
|
||||||
"not_valid_fan_mode": {
|
"not_valid_fan_mode": {
|
||||||
"message": "Fan mode {mode} is not valid. Valid fan modes are: {modes}."
|
"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}."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ from homeassistant.helpers import (
|
|||||||
)
|
)
|
||||||
from homeassistant.helpers.device_registry import DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||||
|
|
||||||
from . import HoneywellData
|
from . import HoneywellData
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -259,7 +260,9 @@ class HoneywellUSThermostat(ClimateEntity):
|
|||||||
self._device.raw_ui_data["HeatLowerSetptLimit"],
|
self._device.raw_ui_data["HeatLowerSetptLimit"],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return DEFAULT_MIN_TEMP
|
return TemperatureConverter.convert(
|
||||||
|
DEFAULT_MIN_TEMP, UnitOfTemperature.CELSIUS, self.temperature_unit
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_temp(self) -> float:
|
def max_temp(self) -> float:
|
||||||
@ -275,7 +278,9 @@ class HoneywellUSThermostat(ClimateEntity):
|
|||||||
self._device.raw_ui_data["HeatUpperSetptLimit"],
|
self._device.raw_ui_data["HeatUpperSetptLimit"],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return DEFAULT_MAX_TEMP
|
return TemperatureConverter.convert(
|
||||||
|
DEFAULT_MAX_TEMP, UnitOfTemperature.CELSIUS, self.temperature_unit
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_humidity(self) -> int | None:
|
def current_humidity(self) -> int | None:
|
||||||
|
@ -85,6 +85,8 @@ async def test_spa_temperature(
|
|||||||
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
hass: HomeAssistant, client: MagicMock, integration: MockConfigEntry
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test spa temperature settings."""
|
"""Test spa temperature settings."""
|
||||||
|
client.temperature_minimum = 110
|
||||||
|
client.temperature_maximum = 250
|
||||||
# flip the spa into F
|
# flip the spa into F
|
||||||
# set temp to a valid number
|
# set temp to a valid number
|
||||||
state = await _patch_spa_settemp(hass, client, 0, 100)
|
state = await _patch_spa_settemp(hass, client, 0, 100)
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import MagicMock, Mock, patch
|
from unittest.mock import MagicMock, Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -17,9 +18,14 @@ from homeassistant.components.climate import (
|
|||||||
HVACMode,
|
HVACMode,
|
||||||
)
|
)
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
|
ATTR_CURRENT_TEMPERATURE,
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
|
ATTR_MAX_TEMP,
|
||||||
|
ATTR_MIN_TEMP,
|
||||||
ATTR_PRESET_MODE,
|
ATTR_PRESET_MODE,
|
||||||
ATTR_SWING_MODE,
|
ATTR_SWING_MODE,
|
||||||
|
ATTR_TARGET_TEMP_HIGH,
|
||||||
|
ATTR_TARGET_TEMP_LOW,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
SERVICE_SET_PRESET_MODE,
|
SERVICE_SET_PRESET_MODE,
|
||||||
SERVICE_SET_SWING_MODE,
|
SERVICE_SET_SWING_MODE,
|
||||||
@ -27,7 +33,13 @@ from homeassistant.components.climate.const import (
|
|||||||
ClimateEntityFeature,
|
ClimateEntityFeature,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
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.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import issue_registry as ir
|
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 "
|
"the auxiliary heater methods in a subclass of ClimateEntity which is deprecated "
|
||||||
"and will be unsupported from Home Assistant 2024.10."
|
"and will be unsupported from Home Assistant 2024.10."
|
||||||
) not in caplog.text
|
) 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
|
||||||
|
@ -263,10 +263,10 @@ async def test_set_temperature_temperature(hass: HomeAssistant, fritz: Mock) ->
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 123},
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 23},
|
||||||
True,
|
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:
|
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_ENTITY_ID: ENTITY_ID,
|
||||||
ATTR_HVAC_MODE: HVACMode.OFF,
|
ATTR_HVAC_MODE: HVACMode.OFF,
|
||||||
ATTR_TEMPERATURE: 123,
|
ATTR_TEMPERATURE: 23,
|
||||||
},
|
},
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
@ -303,7 +303,7 @@ async def test_set_temperature_mode_heat(hass: HomeAssistant, fritz: Mock) -> No
|
|||||||
{
|
{
|
||||||
ATTR_ENTITY_ID: ENTITY_ID,
|
ATTR_ENTITY_ID: ENTITY_ID,
|
||||||
ATTR_HVAC_MODE: HVACMode.HEAT,
|
ATTR_HVAC_MODE: HVACMode.HEAT,
|
||||||
ATTR_TEMPERATURE: 123,
|
ATTR_TEMPERATURE: 23,
|
||||||
},
|
},
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
@ -1097,9 +1097,9 @@ async def setup_comp_9(hass: HomeAssistant) -> None:
|
|||||||
async def test_precision(hass: HomeAssistant) -> None:
|
async def test_precision(hass: HomeAssistant) -> None:
|
||||||
"""Test that setting precision to tenths works as intended."""
|
"""Test that setting precision to tenths works as intended."""
|
||||||
hass.config.units = US_CUSTOMARY_SYSTEM
|
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)
|
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
|
# check that target_temp_step defaults to precision
|
||||||
assert state.attributes.get("target_temp_step") == 0.1
|
assert state.attributes.get("target_temp_step") == 0.1
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ def device():
|
|||||||
mock_device.system_mode = "off"
|
mock_device.system_mode = "off"
|
||||||
mock_device.name = "device1"
|
mock_device.name = "device1"
|
||||||
mock_device.current_temperature = CURRENTTEMPERATURE
|
mock_device.current_temperature = CURRENTTEMPERATURE
|
||||||
|
mock_device.temperature_unit = "C"
|
||||||
mock_device.mac_address = "macaddress1"
|
mock_device.mac_address = "macaddress1"
|
||||||
mock_device.outdoor_temperature = None
|
mock_device.outdoor_temperature = None
|
||||||
mock_device.outdoor_humidity = None
|
mock_device.outdoor_humidity = None
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
ReadOnlyDict({
|
ReadOnlyDict({
|
||||||
'aux_heat': 'off',
|
'aux_heat': 'off',
|
||||||
'current_humidity': 50,
|
'current_humidity': 50,
|
||||||
'current_temperature': -6.7,
|
'current_temperature': 20,
|
||||||
'fan_action': 'idle',
|
'fan_action': 'idle',
|
||||||
'fan_mode': 'auto',
|
'fan_mode': 'auto',
|
||||||
'fan_modes': list([
|
'fan_modes': list([
|
||||||
@ -20,9 +20,9 @@
|
|||||||
<HVACMode.HEAT: 'heat'>,
|
<HVACMode.HEAT: 'heat'>,
|
||||||
]),
|
]),
|
||||||
'max_humidity': 99,
|
'max_humidity': 99,
|
||||||
'max_temp': 1.7,
|
'max_temp': 35,
|
||||||
'min_humidity': 30,
|
'min_humidity': 30,
|
||||||
'min_temp': -13.9,
|
'min_temp': 7,
|
||||||
'permanent_hold': False,
|
'permanent_hold': False,
|
||||||
'preset_mode': 'none',
|
'preset_mode': 'none',
|
||||||
'preset_modes': list([
|
'preset_modes': list([
|
||||||
|
@ -92,14 +92,13 @@ async def test_dynamic_attributes(
|
|||||||
hass: HomeAssistant, device: MagicMock, config_entry: MagicMock
|
hass: HomeAssistant, device: MagicMock, config_entry: MagicMock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test dynamic attributes."""
|
"""Test dynamic attributes."""
|
||||||
|
|
||||||
await init_integration(hass, config_entry)
|
await init_integration(hass, config_entry)
|
||||||
|
|
||||||
entity_id = f"climate.{device.name}"
|
entity_id = f"climate.{device.name}"
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state.state == HVACMode.OFF
|
assert state.state == HVACMode.OFF
|
||||||
attributes = state.attributes
|
attributes = state.attributes
|
||||||
assert attributes["current_temperature"] == -6.7
|
assert attributes["current_temperature"] == 20
|
||||||
assert attributes["current_humidity"] == 50
|
assert attributes["current_humidity"] == 50
|
||||||
|
|
||||||
device.system_mode = "cool"
|
device.system_mode = "cool"
|
||||||
@ -114,7 +113,7 @@ async def test_dynamic_attributes(
|
|||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state.state == HVACMode.COOL
|
assert state.state == HVACMode.COOL
|
||||||
attributes = state.attributes
|
attributes = state.attributes
|
||||||
assert attributes["current_temperature"] == -6.1
|
assert attributes["current_temperature"] == 21
|
||||||
assert attributes["current_humidity"] == 55
|
assert attributes["current_humidity"] == 55
|
||||||
|
|
||||||
device.system_mode = "heat"
|
device.system_mode = "heat"
|
||||||
@ -129,7 +128,7 @@ async def test_dynamic_attributes(
|
|||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state.state == HVACMode.HEAT
|
assert state.state == HVACMode.HEAT
|
||||||
attributes = state.attributes
|
attributes = state.attributes
|
||||||
assert attributes["current_temperature"] == 16.1
|
assert attributes["current_temperature"] == 61
|
||||||
assert attributes["current_humidity"] == 50
|
assert attributes["current_humidity"] == 50
|
||||||
|
|
||||||
device.system_mode = "auto"
|
device.system_mode = "auto"
|
||||||
@ -142,7 +141,7 @@ async def test_dynamic_attributes(
|
|||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state.state == HVACMode.HEAT_COOL
|
assert state.state == HVACMode.HEAT_COOL
|
||||||
attributes = state.attributes
|
attributes = state.attributes
|
||||||
assert attributes["current_temperature"] == 16.1
|
assert attributes["current_temperature"] == 61
|
||||||
assert attributes["current_humidity"] == 50
|
assert attributes["current_humidity"] == 50
|
||||||
|
|
||||||
|
|
||||||
@ -348,7 +347,7 @@ async def test_service_calls_off_mode(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 35},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -362,8 +361,8 @@ async def test_service_calls_off_mode(
|
|||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(35)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(25)
|
||||||
|
|
||||||
device.set_setpoint_heat.reset_mock()
|
device.set_setpoint_heat.reset_mock()
|
||||||
device.set_setpoint_heat.side_effect = aiosomecomfort.SomeComfortError
|
device.set_setpoint_heat.side_effect = aiosomecomfort.SomeComfortError
|
||||||
@ -375,13 +374,13 @@ async def test_service_calls_off_mode(
|
|||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{
|
{
|
||||||
ATTR_ENTITY_ID: entity_id,
|
ATTR_ENTITY_ID: entity_id,
|
||||||
ATTR_TARGET_TEMP_LOW: 25.0,
|
ATTR_TARGET_TEMP_LOW: 24.0,
|
||||||
ATTR_TARGET_TEMP_HIGH: 35.0,
|
ATTR_TARGET_TEMP_HIGH: 34.0,
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(34)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(24)
|
||||||
assert "Invalid temperature" in caplog.text
|
assert "Invalid temperature" in caplog.text
|
||||||
|
|
||||||
device.set_setpoint_heat.reset_mock()
|
device.set_setpoint_heat.reset_mock()
|
||||||
@ -399,14 +398,14 @@ async def test_service_calls_off_mode(
|
|||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(35)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(25)
|
||||||
|
|
||||||
reset_mock(device)
|
reset_mock(device)
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 35},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_heat.assert_not_called()
|
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},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
||||||
blocking=True,
|
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()
|
device.set_hold_cool.reset_mock()
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -525,13 +524,13 @@ async def test_service_calls_cool_mode(
|
|||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{
|
{
|
||||||
ATTR_ENTITY_ID: entity_id,
|
ATTR_ENTITY_ID: entity_id,
|
||||||
ATTR_TARGET_TEMP_LOW: 25.0,
|
ATTR_TARGET_TEMP_LOW: 15.0,
|
||||||
ATTR_TARGET_TEMP_HIGH: 35.0,
|
ATTR_TARGET_TEMP_HIGH: 20.0,
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(20)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(15)
|
||||||
|
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
device.set_setpoint_cool.reset_mock()
|
device.set_setpoint_cool.reset_mock()
|
||||||
@ -543,13 +542,13 @@ async def test_service_calls_cool_mode(
|
|||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{
|
{
|
||||||
ATTR_ENTITY_ID: entity_id,
|
ATTR_ENTITY_ID: entity_id,
|
||||||
ATTR_TARGET_TEMP_LOW: 25.0,
|
ATTR_TARGET_TEMP_LOW: 15.0,
|
||||||
ATTR_TARGET_TEMP_HIGH: 35.0,
|
ATTR_TARGET_TEMP_HIGH: 20.0,
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(20)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(15)
|
||||||
assert "Invalid temperature" in caplog.text
|
assert "Invalid temperature" in caplog.text
|
||||||
|
|
||||||
reset_mock(device)
|
reset_mock(device)
|
||||||
@ -733,10 +732,10 @@ async def test_service_calls_heat_mode(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25},
|
||||||
blocking=True,
|
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.reset_mock()
|
||||||
|
|
||||||
device.set_hold_heat.side_effect = aiosomecomfort.SomeComfortError
|
device.set_hold_heat.side_effect = aiosomecomfort.SomeComfortError
|
||||||
@ -744,10 +743,10 @@ async def test_service_calls_heat_mode(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25},
|
||||||
blocking=True,
|
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.reset_mock()
|
||||||
assert "Invalid temperature" in caplog.text
|
assert "Invalid temperature" in caplog.text
|
||||||
|
|
||||||
@ -756,10 +755,10 @@ async def test_service_calls_heat_mode(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25},
|
||||||
blocking=True,
|
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.reset_mock()
|
||||||
|
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
@ -773,8 +772,8 @@ async def test_service_calls_heat_mode(
|
|||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(35)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(25)
|
||||||
|
|
||||||
device.set_setpoint_heat.reset_mock()
|
device.set_setpoint_heat.reset_mock()
|
||||||
device.set_setpoint_heat.side_effect = aiosomecomfort.SomeComfortError
|
device.set_setpoint_heat.side_effect = aiosomecomfort.SomeComfortError
|
||||||
@ -789,8 +788,8 @@ async def test_service_calls_heat_mode(
|
|||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_with(95)
|
device.set_setpoint_cool.assert_called_with(35)
|
||||||
device.set_setpoint_heat.assert_called_with(77)
|
device.set_setpoint_heat.assert_called_with(25)
|
||||||
assert "Invalid temperature" in caplog.text
|
assert "Invalid temperature" in caplog.text
|
||||||
|
|
||||||
reset_mock(device)
|
reset_mock(device)
|
||||||
@ -984,8 +983,8 @@ async def test_service_calls_auto_mode(
|
|||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
device.set_setpoint_cool.assert_called_once_with(95)
|
device.set_setpoint_cool.assert_called_once_with(35)
|
||||||
device.set_setpoint_heat.assert_called_once_with(77)
|
device.set_setpoint_heat.assert_called_once_with(25)
|
||||||
|
|
||||||
reset_mock(device)
|
reset_mock(device)
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
@ -766,7 +766,7 @@ async def test_service_climate_swing_update(
|
|||||||
("temperature", "result", "do_config"),
|
("temperature", "result", "do_config"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
35,
|
31,
|
||||||
[0x00],
|
[0x00],
|
||||||
{
|
{
|
||||||
CONF_CLIMATES: [
|
CONF_CLIMATES: [
|
||||||
@ -781,7 +781,7 @@ async def test_service_climate_swing_update(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
36,
|
32,
|
||||||
[0x00, 0x00],
|
[0x00, 0x00],
|
||||||
{
|
{
|
||||||
CONF_CLIMATES: [
|
CONF_CLIMATES: [
|
||||||
@ -796,7 +796,7 @@ async def test_service_climate_swing_update(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
37.5,
|
33.5,
|
||||||
[0x00, 0x00],
|
[0x00, 0x00],
|
||||||
{
|
{
|
||||||
CONF_CLIMATES: [
|
CONF_CLIMATES: [
|
||||||
@ -811,7 +811,7 @@ async def test_service_climate_swing_update(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"39",
|
"34",
|
||||||
[0x00, 0x00, 0x00, 0x00],
|
[0x00, 0x00, 0x00, 0x00],
|
||||||
{
|
{
|
||||||
CONF_CLIMATES: [
|
CONF_CLIMATES: [
|
||||||
|
@ -654,11 +654,11 @@ async def test_set_target_temperature(
|
|||||||
assert state.state == "heat"
|
assert state.state == "heat"
|
||||||
mqtt_mock.async_publish.assert_called_once_with("mode-topic", "heat", 0, False)
|
mqtt_mock.async_publish.assert_called_once_with("mode-topic", "heat", 0, False)
|
||||||
mqtt_mock.async_publish.reset_mock()
|
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)
|
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(
|
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
|
# 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)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get("temperature") is None
|
assert state.attributes.get("temperature") is None
|
||||||
await common.async_set_hvac_mode(hass, "heat", ENTITY_CLIMATE)
|
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)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get("temperature") is None
|
assert state.attributes.get("temperature") is None
|
||||||
|
|
||||||
@ -1590,13 +1590,13 @@ async def test_set_and_templates(
|
|||||||
assert state.attributes.get("swing_mode") == "on"
|
assert state.attributes.get("swing_mode") == "on"
|
||||||
|
|
||||||
# Temperature
|
# 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(
|
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()
|
mqtt_mock.async_publish.reset_mock()
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get("temperature") == 47
|
assert state.attributes.get("temperature") == 35
|
||||||
|
|
||||||
# Temperature Low/High
|
# Temperature Low/High
|
||||||
await common.async_set_temperature(
|
await common.async_set_temperature(
|
||||||
|
@ -14,7 +14,7 @@ from homeassistant.components.climate import (
|
|||||||
HVACMode,
|
HVACMode,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
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}
|
"c50f167537524366a5af7aa3942feb1e", {"setpoint": 25.0}
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
@ -400,6 +400,10 @@ async def test_climate_temperatures(
|
|||||||
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
|
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
|
||||||
return_value={"result": {"status": "Success"}},
|
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(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
@ -410,7 +414,7 @@ async def test_climate_temperatures(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state2 = hass.states.get("climate.hallway")
|
state2 = hass.states.get("climate.hallway")
|
||||||
assert state2.attributes["temperature"] == 20
|
assert state2.attributes["temperature"] == 19
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch(
|
patch(
|
||||||
|
@ -199,7 +199,7 @@ async def test_climate(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: [entity_id], ATTR_TEMPERATURE: 25},
|
{ATTR_ENTITY_ID: [entity_id], ATTR_TEMPERATURE: 34},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -120,12 +120,13 @@ async def test_set_temperature(
|
|||||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mocked_hub: Device
|
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mocked_hub: Device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that set_temperature service calls the setter."""
|
"""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(
|
await setup_platform_for_device(
|
||||||
hass, mock_config_entry, Platform.CLIMATE, mocked_hub
|
hass, mock_config_entry, Platform.CLIMATE, mocked_hub
|
||||||
)
|
)
|
||||||
|
|
||||||
mocked_thermostat = mocked_hub.children[0]
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
@ -264,10 +264,10 @@ async def test_service_calls(
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 15},
|
{ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 16},
|
||||||
blocking=True,
|
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()
|
mock_instance.set_mode.reset_mock()
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user