Change algo using underlying internal temp
This commit is contained in:
7
copy-to-forum.txt
Normal file
7
copy-to-forum.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Before copying to forum you need to replace relative images by this command into VSCode:
|
||||||
|
|
||||||
|
Search :
|
||||||
|
\(images/(.*).png\)
|
||||||
|
|
||||||
|
Replace with:
|
||||||
|
(https://github.com/jmcollin78/versatile_thermostat/blob/main/images/$1.png?raw=true)
|
||||||
@@ -194,8 +194,45 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
|
|
||||||
self._last_regulation_change = now
|
self._last_regulation_change = now
|
||||||
for under in self._underlyings:
|
for under in self._underlyings:
|
||||||
|
# issue 348 - use device temperature if configured as offset
|
||||||
|
offset_temp = 0
|
||||||
|
device_temp = 0
|
||||||
|
if (
|
||||||
|
# regulation can use the device_temp
|
||||||
|
self.auto_regulation_use_device_temp
|
||||||
|
# and we have access to the device temp
|
||||||
|
and (device_temp := under.underlying_current_temperature) is not None
|
||||||
|
# and target is not reach (ie we need regulation)
|
||||||
|
and (
|
||||||
|
(
|
||||||
|
self.hvac_mode == HVACMode.COOL
|
||||||
|
and self.target_temperature < self.current_temperature
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
self.hvac_mode == HVACMode.HEAT
|
||||||
|
and self.target_temperature > self.current_temperature
|
||||||
|
)
|
||||||
|
)
|
||||||
|
):
|
||||||
|
offset_temp = self.current_temperature - device_temp
|
||||||
|
|
||||||
|
if self.hvac_mode == HVACMode.COOL:
|
||||||
|
target_temp = self.regulated_target_temp - offset_temp
|
||||||
|
else:
|
||||||
|
target_temp = self.regulated_target_temp + offset_temp
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s - the device offset temp for regulation is %.2f - internal temp is %.2f. Nes target is %.2f",
|
||||||
|
self,
|
||||||
|
offset_temp,
|
||||||
|
device_temp,
|
||||||
|
target_temp,
|
||||||
|
)
|
||||||
|
|
||||||
await under.set_temperature(
|
await under.set_temperature(
|
||||||
self.regulated_target_temp, self._attr_max_temp, self._attr_min_temp
|
target_temp,
|
||||||
|
self._attr_max_temp,
|
||||||
|
self._attr_min_temp,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _send_auto_fan_mode(self):
|
async def _send_auto_fan_mode(self):
|
||||||
|
|||||||
@@ -568,23 +568,9 @@ class UnderlyingClimate(UnderlyingEntity):
|
|||||||
if not self.is_initialized:
|
if not self.is_initialized:
|
||||||
return
|
return
|
||||||
|
|
||||||
# issue 348 - use device temperature if configured as offset
|
|
||||||
offset_temp = 0
|
|
||||||
if self._thermostat.auto_regulation_use_device_temp and hasattr(
|
|
||||||
self._underlying_climate, "current_temperature"
|
|
||||||
):
|
|
||||||
device_temp = self._underlying_climate.current_temperature
|
|
||||||
offset_temp = device_temp - self._thermostat.current_temperature
|
|
||||||
_LOGGER.debug(
|
|
||||||
"%s - the device offset temp for regulation is %.2f - internal temp is %.2f",
|
|
||||||
self,
|
|
||||||
offset_temp,
|
|
||||||
device_temp,
|
|
||||||
)
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
ATTR_ENTITY_ID: self._entity_id,
|
ATTR_ENTITY_ID: self._entity_id,
|
||||||
"temperature": self.cap_sent_value(temperature + offset_temp),
|
"temperature": self.cap_sent_value(temperature),
|
||||||
"target_temp_high": max_temp,
|
"target_temp_high": max_temp,
|
||||||
"target_temp_low": min_temp,
|
"target_temp_low": min_temp,
|
||||||
}
|
}
|
||||||
@@ -686,6 +672,18 @@ class UnderlyingClimate(UnderlyingEntity):
|
|||||||
return False
|
return False
|
||||||
return self._underlying_climate.is_aux_heat
|
return self._underlying_climate.is_aux_heat
|
||||||
|
|
||||||
|
@property
|
||||||
|
def underlying_current_temperature(self) -> float | None:
|
||||||
|
"""Get the underlying current_temperature if it exists
|
||||||
|
and if initialized"""
|
||||||
|
if not self.is_initialized:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not hasattr(self._underlying_climate, "current_temperature"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self._underlying_climate.current_temperature
|
||||||
|
|
||||||
def turn_aux_heat_on(self) -> None:
|
def turn_aux_heat_on(self) -> None:
|
||||||
"""Turn auxiliary heater on."""
|
"""Turn auxiliary heater on."""
|
||||||
if not self.is_initialized:
|
if not self.is_initialized:
|
||||||
|
|||||||
@@ -421,18 +421,6 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
assert entity.is_regulated is True
|
assert entity.is_regulated is True
|
||||||
assert entity.auto_regulation_use_device_temp is True
|
assert entity.auto_regulation_use_device_temp is True
|
||||||
|
|
||||||
assert entity.hvac_mode is HVACMode.OFF
|
|
||||||
assert entity.hvac_action is HVACAction.OFF
|
|
||||||
assert entity.target_temperature == entity.min_temp
|
|
||||||
assert entity.preset_modes == [
|
|
||||||
PRESET_NONE,
|
|
||||||
PRESET_FROST_PROTECTION,
|
|
||||||
PRESET_ECO,
|
|
||||||
PRESET_COMFORT,
|
|
||||||
PRESET_BOOST,
|
|
||||||
]
|
|
||||||
assert entity.preset_mode is PRESET_NONE
|
|
||||||
|
|
||||||
# 1. Activate the heating by changing HVACMode and temperature
|
# 1. Activate the heating by changing HVACMode and temperature
|
||||||
# Select a hvacmode, presence and preset
|
# Select a hvacmode, presence and preset
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
@@ -442,7 +430,11 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
await send_temperature_change_event(entity, 18, event_timestamp)
|
await send_temperature_change_event(entity, 18, event_timestamp)
|
||||||
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
await send_ext_temperature_change_event(entity, 10, event_timestamp)
|
||||||
|
|
||||||
# 2. set manual target temp (at now - 7) -> the regulation should occurs
|
# 2. set manual target temp (at now - 7) -> no regulation should occurs
|
||||||
|
# room temp is 18
|
||||||
|
# target is 16
|
||||||
|
# internal heater temp is 15
|
||||||
|
fake_underlying_climate.set_current_temperature(15)
|
||||||
event_timestamp = now - timedelta(minutes=7)
|
event_timestamp = now - timedelta(minutes=7)
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
@@ -456,7 +448,7 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
assert entity.hvac_action == HVACAction.HEATING
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
assert entity.preset_mode == PRESET_NONE # Manual mode
|
assert entity.preset_mode == PRESET_NONE # Manual mode
|
||||||
|
|
||||||
# the regulated temperature should be lower
|
# the regulated temperature should be higher
|
||||||
assert entity.regulated_target_temp < entity.target_temperature
|
assert entity.regulated_target_temp < entity.target_temperature
|
||||||
# The calcul is the following: 16 + (16 - 18) x 0.4 (strong) + 0 x ki - 1 (device offset)
|
# The calcul is the following: 16 + (16 - 18) x 0.4 (strong) + 0 x ki - 1 (device offset)
|
||||||
assert (
|
assert (
|
||||||
@@ -471,7 +463,8 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
"set_temperature",
|
"set_temperature",
|
||||||
{
|
{
|
||||||
"entity_id": "climate.mock_climate",
|
"entity_id": "climate.mock_climate",
|
||||||
"temperature": 12.0, # because device offset is -3 (15 - 18)
|
# because device offset is -3 but not used because target is reach
|
||||||
|
"temperature": 15.0,
|
||||||
"target_temp_high": 30,
|
"target_temp_high": 30,
|
||||||
"target_temp_low": 15,
|
"target_temp_low": 15,
|
||||||
},
|
},
|
||||||
@@ -480,19 +473,23 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 3. change temperature so that the regulated temperature should slow down
|
# 3. change temperature so that the regulated temperature should slow down
|
||||||
fake_underlying_climate.set_current_temperature(27)
|
# room temp is 15
|
||||||
|
# target is 18
|
||||||
|
# internal heater temp is 13
|
||||||
|
fake_underlying_climate.set_current_temperature(13)
|
||||||
|
await entity.async_set_temperature(temperature=18)
|
||||||
|
await send_ext_temperature_change_event(entity, 9, event_timestamp)
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=5)
|
event_timestamp = now - timedelta(minutes=5)
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
return_value=event_timestamp,
|
return_value=event_timestamp,
|
||||||
), patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call:
|
), patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call:
|
||||||
await send_temperature_change_event(entity, 23, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
await send_ext_temperature_change_event(entity, 19, event_timestamp)
|
|
||||||
|
|
||||||
# the regulated temperature should be under (device offset is -3)
|
# the regulated temperature should be under (device offset is -2)
|
||||||
assert entity.regulated_target_temp < entity.target_temperature
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
assert entity.regulated_target_temp == 12.5
|
assert entity.regulated_target_temp == 19.4 # 18 + 1.4
|
||||||
|
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
[
|
[
|
||||||
@@ -501,7 +498,42 @@ async def test_over_climate_regulation_use_device_temp(
|
|||||||
"set_temperature",
|
"set_temperature",
|
||||||
{
|
{
|
||||||
"entity_id": "climate.mock_climate",
|
"entity_id": "climate.mock_climate",
|
||||||
"temperature": 16.5, # because device offset is +4 (27 - 23)
|
"temperature": 21.4, # 19.4 + 2
|
||||||
|
"target_temp_high": 30,
|
||||||
|
"target_temp_low": 15,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# 4. In cool mode
|
||||||
|
# room temp is 25
|
||||||
|
# target is 23
|
||||||
|
# internal heater temp is 27
|
||||||
|
await entity.async_set_hvac_mode(HVACMode.COOL)
|
||||||
|
await entity.async_set_temperature(temperature=23)
|
||||||
|
fake_underlying_climate.set_current_temperature(27)
|
||||||
|
await send_ext_temperature_change_event(entity, 30, event_timestamp)
|
||||||
|
|
||||||
|
event_timestamp = now - timedelta(minutes=3)
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.commons.NowClass.get_now",
|
||||||
|
return_value=event_timestamp,
|
||||||
|
), patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call:
|
||||||
|
await send_temperature_change_event(entity, 25, event_timestamp)
|
||||||
|
|
||||||
|
# the regulated temperature should be upper (device offset is +2)
|
||||||
|
assert entity.regulated_target_temp < entity.target_temperature
|
||||||
|
assert entity.regulated_target_temp == 22.9
|
||||||
|
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.service_call(
|
||||||
|
"climate",
|
||||||
|
"set_temperature",
|
||||||
|
{
|
||||||
|
"entity_id": "climate.mock_climate",
|
||||||
|
"temperature": 24.9, # 22.9 + 2° of offset
|
||||||
"target_temp_high": 30,
|
"target_temp_high": 30,
|
||||||
"target_temp_low": 15,
|
"target_temp_low": 15,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user