Skip to content

Commit

Permalink
More fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gjohansson-ST committed Aug 14, 2024
1 parent 0aa8088 commit 12d0374
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 12 deletions.
63 changes: 52 additions & 11 deletions homeassistant/components/climate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,37 @@ def state_attributes(self) -> dict[str, Any]:
data[ATTR_TARGET_TEMP_LOW] = show_temp(
hass, self.target_temperature_low, temperature_unit, precision
)
if hasattr(self, "min_temperature_range"):
data[ATTR_MIN_TEMP_RANGE] = self.min_temperature_range
if (
hasattr(self, "min_temperature_range")
and (min_temp_range := self.min_temperature_range) is not None
):
data[ATTR_MIN_TEMP_RANGE] = min_temp_range
if (
self.hass.config.units.temperature_unit != temperature_unit
and temperature_unit == UnitOfTemperature.CELSIUS
and (
show_temp_range := show_temp(
hass,
min_temp_range,
temperature_unit,
precision,
)
)
):
data[ATTR_MIN_TEMP_RANGE] = show_temp_range - 32
elif (
self.hass.config.units.temperature_unit != temperature_unit
and temperature_unit == UnitOfTemperature.FAHRENHEIT
and (
show_temp_range := show_temp(
hass,
min_temp_range,
temperature_unit,
precision,
)
)
):
data[ATTR_MIN_TEMP_RANGE] = show_temp_range + 32

if (current_humidity := self.current_humidity) is not None:
data[ATTR_CURRENT_HUMIDITY] = current_humidity
Expand Down Expand Up @@ -961,9 +990,12 @@ async def async_service_temperature_set(
else:
kwargs[value] = temp

if not hasattr(entity, "min_temperature_range"):
await entity.async_set_temperature(**kwargs)
return

if (
hasattr(entity, "min_temperature_range")
and (min_temp_range := entity.min_temperature_range)
(min_temp_range := entity.min_temperature_range)
and (target_low_temp := kwargs.get(ATTR_TARGET_TEMP_LOW))
and (target_high_temp := kwargs.get(ATTR_TARGET_TEMP_HIGH))
and (target_high_temp - target_low_temp) < min_temp_range
Expand All @@ -973,27 +1005,36 @@ async def async_service_temperature_set(
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="low_temp_higher_than_high_temp",
translation_placeholders={
"min_temp": str(target_low_temp),
"max_temp": str(target_high_temp),
},
)

# Ensure deadband between target temperatures.
initial_low_temp = target_low_temp
if (target_high_temp - target_low_temp) < min_temp_range:
target_low_temp = target_high_temp - min_temp_range

# Guard target_low_temp isn't lower than entity low_temp
if target_low_temp < min_temp:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="range_to_small",
translation_key="outside_tolerance",
translation_placeholders={
"min_temp": str(target_low_temp),
"max_temp": str(target_high_temp),
"min_temp": str(min_temp),
"target_low": str(target_low_temp),
"range": str(min_temp_range),
},
)

_LOGGER.debug(
"Moved low temperature from %d %s to %d %s due to range %d and high temperature is %d %s",
initial_low_temp,
temp_unit,
target_low_temp,
temp_unit,
min_temp_range,
target_high_temp,
temp_unit,
)

kwargs[ATTR_TARGET_TEMP_HIGH] = target_high_temp
kwargs[ATTR_TARGET_TEMP_LOW] = target_low_temp

Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/climate/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@
},
"temp_out_of_range": {
"message": "Provided temperature {check_temp} is not valid. Accepted range is {min_temp} to {max_temp}."
},
"low_temp_higher_than_high_temp": {
"message": "Target low temperature can not be higher than target high temperature."
},
"outside_tolerance": {
"message": "Ensuring range of {range} made target low temperature {target_low} move out of the allowed minimum temperature {min_temp}."
}
}
}
57 changes: 56 additions & 1 deletion tests/components/climate/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,7 @@ async def async_setup_entry_climate_platform(


async def test_temperature_range_deadband(
hass: HomeAssistant, config_flow_fixture: None
hass: HomeAssistant, config_flow_fixture: None, caplog: pytest.LogCaptureFixture
) -> None:
"""Test temperature range with deadband."""

Expand All @@ -1305,6 +1305,7 @@ class MockClimateEntityTargetTemp(MockClimateEntity):
| ClimateEntityFeature.SWING_MODE
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_min_temperature_range = 3
_attr_target_temperature_high = 16
_attr_target_temperature_low = 11
Expand Down Expand Up @@ -1401,6 +1402,11 @@ async def async_setup_entry_climate_platform(
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 20.0
assert state.attributes[ATTR_MIN_TEMP_RANGE] == 3.0

assert (
"Moved low temperature from 18 °C to 17 °C due to range 3 and high temperature is 20 °C"
in caplog.text
)

# Raises as not allowed for min temp to be higher than high temp
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
Expand All @@ -1426,3 +1432,52 @@ async def async_setup_entry_climate_platform(
},
blocking=True,
)

hass.config.units.temperature_unit = UnitOfTemperature.FAHRENHEIT

# Does not raise as 5 degrees Fahrenheit is within the 3 degrees Celsius range
await hass.services.async_call(
DOMAIN,
SERVICE_SET_TEMPERATURE,
{
"entity_id": "climate.test",
ATTR_TARGET_TEMP_HIGH: 60, # 15.5 C
ATTR_TARGET_TEMP_LOW: 55, # 12.7 C
},
blocking=True,
)
state = hass.states.get("climate.test")
assert state.attributes[ATTR_TARGET_TEMP_LOW] == 55.0
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 60.0
assert state.attributes[ATTR_MIN_TEMP_RANGE] == 5.0

await hass.services.async_call(
DOMAIN,
SERVICE_SET_TEMPERATURE,
{
"entity_id": "climate.test",
ATTR_TARGET_TEMP_HIGH: 60,
ATTR_TARGET_TEMP_LOW: 56,
},
blocking=True,
)
state = hass.states.get("climate.test")
assert state.attributes[ATTR_TARGET_TEMP_LOW] == 55.0
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 60.0
assert state.attributes[ATTR_MIN_TEMP_RANGE] == 5.0

with pytest.raises(ServiceValidationError):
await hass.services.async_call(
DOMAIN,
SERVICE_SET_TEMPERATURE,
{
"entity_id": "climate.test",
ATTR_TARGET_TEMP_HIGH: 54,
ATTR_TARGET_TEMP_LOW: 50,
},
blocking=True,
)
state = hass.states.get("climate.test")
assert state.attributes[ATTR_TARGET_TEMP_LOW] == 55.0
assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 60.0
assert state.attributes[ATTR_MIN_TEMP_RANGE] == 5.0

0 comments on commit 12d0374

Please sign in to comment.