Enhance temperature regulation when working with internal device temperature (#453)
* [feature/autoregulation-send-for-underlyingtemp] Do not forget regulation send when using underlying device temperature for offset * [feature/autoregulation-send-for-underlyingtemp] Add unit test for dtemp = 0 * [feature/autoregulation-send-for-underlyingtemp] Test with dtemp lower than 0.5 * [feature/autoregulation-send-for-underlyingtemp] Comments
This commit is contained in:
@@ -168,11 +168,17 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
|
|
||||||
_LOGGER.info("%s - regulation calculation will be done", self)
|
_LOGGER.info("%s - regulation calculation will be done", self)
|
||||||
|
|
||||||
|
# use _attr_target_temperature_step to round value if _auto_regulation_dtemp is equal to 0
|
||||||
|
regulation_step = self._auto_regulation_dtemp if self._auto_regulation_dtemp else self._attr_target_temperature_step
|
||||||
|
_LOGGER.debug("%s - usage of regulation_step: %.2f ",
|
||||||
|
self,
|
||||||
|
regulation_step)
|
||||||
|
|
||||||
new_regulated_temp = round_to_nearest(
|
new_regulated_temp = round_to_nearest(
|
||||||
self._regulation_algo.calculate_regulated_temperature(
|
self._regulation_algo.calculate_regulated_temperature(
|
||||||
self.current_temperature, self._cur_ext_temp
|
self.current_temperature, self._cur_ext_temp
|
||||||
),
|
),
|
||||||
self._auto_regulation_dtemp,
|
regulation_step,
|
||||||
)
|
)
|
||||||
dtemp = new_regulated_temp - self._regulated_target_temp
|
dtemp = new_regulated_temp - self._regulated_target_temp
|
||||||
|
|
||||||
@@ -216,7 +222,7 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
):
|
):
|
||||||
offset_temp = device_temp - self.current_temperature
|
offset_temp = device_temp - self.current_temperature
|
||||||
|
|
||||||
target_temp = round_to_nearest(self.regulated_target_temp + offset_temp, self._auto_regulation_dtemp)
|
target_temp = round_to_nearest(self.regulated_target_temp + offset_temp, regulation_step)
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s - The device offset temp for regulation is %.2f - internal temp is %.2f. New target is %.2f",
|
"%s - The device offset temp for regulation is %.2f - internal temp is %.2f. New target is %.2f",
|
||||||
|
|||||||
@@ -544,3 +544,116 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_over_climate_regulation_dtemp_null(
|
||||||
|
hass: HomeAssistant, skip_hass_states_is_state, skip_send_event
|
||||||
|
):
|
||||||
|
"""Test the regulation of an over climate thermostat with no Dtemp limitation"""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title="TheOverClimateMockName",
|
||||||
|
unique_id="uniqueId",
|
||||||
|
# This is include a medium regulation
|
||||||
|
data=PARTIAL_CLIMATE_AC_CONFIG | {CONF_AUTO_REGULATION_DTEMP: 0, CONF_STEP_TEMPERATURE: 0.1},
|
||||||
|
)
|
||||||
|
|
||||||
|
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||||
|
now: datetime = datetime.now(tz=tz)
|
||||||
|
fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {})
|
||||||
|
|
||||||
|
# Creates the regulated VTherm over climate
|
||||||
|
# change temperature so that the heating will start
|
||||||
|
event_timestamp = now - timedelta(minutes=20)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
|
return_value=event_timestamp,
|
||||||
|
), patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||||
|
return_value=fake_underlying_climate,
|
||||||
|
):
|
||||||
|
entity = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
|
||||||
|
|
||||||
|
assert entity
|
||||||
|
assert isinstance(entity, ThermostatOverClimate)
|
||||||
|
|
||||||
|
assert entity.name == "TheOverClimateMockName"
|
||||||
|
assert entity.is_over_climate is True
|
||||||
|
assert entity.is_regulated is True
|
||||||
|
|
||||||
|
# Activate the heating by changing HVACMode and temperature
|
||||||
|
# Select a hvacmode, presence and preset
|
||||||
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
|
assert entity.hvac_action == HVACAction.OFF
|
||||||
|
|
||||||
|
# change temperature so that the heating will start
|
||||||
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
|
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||||
|
|
||||||
|
# set manual target temp
|
||||||
|
event_timestamp = now - timedelta(minutes=17)
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
|
return_value=event_timestamp,
|
||||||
|
):
|
||||||
|
await entity.async_set_temperature(temperature=20)
|
||||||
|
|
||||||
|
fake_underlying_climate.set_hvac_action(
|
||||||
|
HVACAction.HEATING
|
||||||
|
) # simulate under cooling
|
||||||
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
|
assert entity.preset_mode == PRESET_NONE # Manual mode
|
||||||
|
|
||||||
|
# the regulated temperature should be lower
|
||||||
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
|
assert (
|
||||||
|
entity.regulated_target_temp == 20 + 2.4
|
||||||
|
) # In medium we could go up to +3 degre
|
||||||
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
|
|
||||||
|
# change temperature so that the regulated temperature should slow down
|
||||||
|
event_timestamp = now - timedelta(minutes=15)
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
|
return_value=event_timestamp,
|
||||||
|
):
|
||||||
|
await send_temperature_change_event(entity, 19, event_timestamp)
|
||||||
|
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||||
|
|
||||||
|
# the regulated temperature should be greater
|
||||||
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
|
assert (
|
||||||
|
entity.regulated_target_temp == 20 + 0.9
|
||||||
|
)
|
||||||
|
|
||||||
|
# change temperature so that the regulated temperature should slow down
|
||||||
|
event_timestamp = now - timedelta(minutes=13)
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
|
return_value=event_timestamp,
|
||||||
|
):
|
||||||
|
await send_temperature_change_event(entity, 20, event_timestamp)
|
||||||
|
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||||
|
|
||||||
|
# the regulated temperature should be greater
|
||||||
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
|
assert (
|
||||||
|
entity.regulated_target_temp == 20 + 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
old_regulated_temp = entity.regulated_target_temp
|
||||||
|
# Test if a small temperature change is taken into account : change temperature so that dtemp < 0.5 and time is > period_min (+ 3min)
|
||||||
|
event_timestamp = now - timedelta(minutes=10)
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
|
return_value=event_timestamp,
|
||||||
|
):
|
||||||
|
await send_temperature_change_event(entity, 19.6, event_timestamp)
|
||||||
|
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||||
|
|
||||||
|
# the regulated temperature should be greater. This does not work if dtemp is not null
|
||||||
|
assert entity.regulated_target_temp > old_regulated_temp
|
||||||
Reference in New Issue
Block a user