Calculate offset_calibration as room_temp - local_temp
Fix hvac_action calculation
This commit is contained in:
@@ -504,7 +504,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
||||
entry_infos.get(CONF_WINDOW_ACTION) or CONF_WINDOW_TURN_OFF
|
||||
)
|
||||
|
||||
self._max_on_percent = api._max_on_percent
|
||||
self._max_on_percent = api.max_on_percent
|
||||
|
||||
_LOGGER.debug(
|
||||
"%s - Creation of a new VersatileThermostat entity: unique_id=%s",
|
||||
|
||||
@@ -464,9 +464,9 @@ class RegulationParamVeryStrong:
|
||||
kp: float = 0.6
|
||||
ki: float = 0.1
|
||||
k_ext: float = 0.2
|
||||
offset_max: float = 4
|
||||
offset_max: float = 8
|
||||
stabilization_threshold: float = 0.1
|
||||
accumulated_error_threshold: float = 30
|
||||
accumulated_error_threshold: float = 80
|
||||
|
||||
|
||||
class EventType(Enum):
|
||||
|
||||
@@ -151,15 +151,13 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
||||
"""True if the Thermostat is over_climate"""
|
||||
return True
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> HVACAction | None:
|
||||
"""Returns the current hvac_action by checking all hvac_action of the underlyings"""
|
||||
|
||||
def calculate_hvac_action(self, under_list: list) -> HVACAction | None:
|
||||
"""Calculate an hvac action based on the hvac_action of the list in argument"""
|
||||
# if one not IDLE or OFF -> return it
|
||||
# else if one IDLE -> IDLE
|
||||
# else OFF
|
||||
one_idle = False
|
||||
for under in self._underlyings:
|
||||
for under in under_list:
|
||||
if (action := under.hvac_action) not in [
|
||||
HVACAction.IDLE,
|
||||
HVACAction.OFF,
|
||||
@@ -171,6 +169,11 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
||||
return HVACAction.IDLE
|
||||
return HVACAction.OFF
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> HVACAction | None:
|
||||
"""Returns the current hvac_action by checking all hvac_action of the underlyings"""
|
||||
return self.calculate_hvac_action(self._underlyings)
|
||||
|
||||
@overrides
|
||||
async def _async_internal_set_temperature(self, temperature: float):
|
||||
"""Set the target temperature and the target temperature of underlying climate if any"""
|
||||
|
||||
@@ -5,7 +5,7 @@ import logging
|
||||
from datetime import datetime
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.components.climate import HVACMode
|
||||
from homeassistant.components.climate import HVACMode, HVACAction
|
||||
|
||||
from .underlyings import UnderlyingSonoffTRVZB
|
||||
|
||||
@@ -96,6 +96,7 @@ class ThermostatOverSonoffTRVZB(ThermostatOverClimate):
|
||||
offset_calibration_entity_id=offset,
|
||||
opening_degree_entity_id=opening,
|
||||
closing_degree_entity_id=closing,
|
||||
climate_underlying=self._underlyings[idx],
|
||||
)
|
||||
self._underlyings_sonoff_trvzb.append(under)
|
||||
|
||||
@@ -240,3 +241,9 @@ class ThermostatOverSonoffTRVZB(ThermostatOverClimate):
|
||||
return 0
|
||||
else:
|
||||
return self._valve_open_percent
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> HVACAction | None:
|
||||
"""Returns the current hvac_action by checking all hvac_action of the _underlyings_sonoff_trvzb"""
|
||||
|
||||
return self.calculate_hvac_action(self._underlyings_sonoff_trvzb)
|
||||
|
||||
@@ -1030,15 +1030,18 @@ class UnderlyingSonoffTRVZB(UnderlyingValve):
|
||||
offset_calibration_entity_id: str,
|
||||
opening_degree_entity_id: str,
|
||||
closing_degree_entity_id: str,
|
||||
climate_underlying: UnderlyingClimate,
|
||||
) -> None:
|
||||
"""Initialize the underlying Sonoff TRV"""
|
||||
super().__init__(hass, thermostat, opening_degree_entity_id)
|
||||
self._offset_calibration_entity_id = offset_calibration_entity_id
|
||||
self._opening_degree_entity_id = opening_degree_entity_id
|
||||
self._closing_degree_entity_id = closing_degree_entity_id
|
||||
self._climate_underlying = climate_underlying
|
||||
self._is_min_max_initialized = False
|
||||
self._max_opening_degree = None
|
||||
self._min_offset_calibration = None
|
||||
self._max_offset_calibration = None
|
||||
|
||||
async def send_percent_open(self):
|
||||
"""Send the percent open to the underlying valve"""
|
||||
@@ -1052,6 +1055,9 @@ class UnderlyingSonoffTRVZB(UnderlyingValve):
|
||||
self._min_offset_calibration = self._hass.states.get(
|
||||
self._offset_calibration_entity_id
|
||||
).attributes.get("min")
|
||||
self._max_offset_calibration = self._hass.states.get(
|
||||
self._offset_calibration_entity_id
|
||||
).attributes.get("max")
|
||||
|
||||
self._is_min_max_initialized = (
|
||||
self._max_opening_degree is not None
|
||||
@@ -1067,15 +1073,32 @@ class UnderlyingSonoffTRVZB(UnderlyingValve):
|
||||
# Send opening_degree
|
||||
await super().send_percent_open()
|
||||
|
||||
# Send closing_degree. TODO 100 hard-coded or take the max of the _closing_degree_entity_id ?
|
||||
# Send closing_degree.
|
||||
await self._send_value_to_number(
|
||||
self._closing_degree_entity_id,
|
||||
self._max_opening_degree - self._percent_open,
|
||||
closing_degree := self._max_opening_degree - self._percent_open,
|
||||
)
|
||||
|
||||
# send offset_calibration to the min value
|
||||
await self._send_value_to_number(
|
||||
self._offset_calibration_entity_id, self._min_offset_calibration
|
||||
# send offset_calibration to the difference between target temp and local temp
|
||||
offset = 0
|
||||
if (
|
||||
local_temp := self._climate_underlying.underlying_current_temperature
|
||||
) is not None and (
|
||||
room_temp := self._thermostat.current_temperature
|
||||
) is not None:
|
||||
offset = min(
|
||||
self._max_offset_calibration,
|
||||
max(self._min_offset_calibration, room_temp - local_temp),
|
||||
)
|
||||
|
||||
await self._send_value_to_number(self._offset_calibration_entity_id, offset)
|
||||
|
||||
_LOGGER.debug(
|
||||
"%s - SonoffTRVZB - I have sent offset_calibration=%s opening_degree=%s closing_degree=%s",
|
||||
self,
|
||||
offset,
|
||||
self._percent_open,
|
||||
closing_degree,
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@@ -179,7 +179,8 @@ class VersatileThermostatAPI(dict):
|
||||
# ):
|
||||
# await entity.init_presets(self.find_central_configuration())
|
||||
|
||||
# A little hack to test if the climate is a VTherm. Cannot use isinstance due to circular dependency of BaseThermostat
|
||||
# A little hack to test if the climate is a VTherm. Cannot use isinstance
|
||||
# due to circular dependency of BaseThermostat
|
||||
if (
|
||||
entity.device_info
|
||||
and entity.device_info.get("model", None) == DOMAIN
|
||||
@@ -249,6 +250,11 @@ class VersatileThermostatAPI(dict):
|
||||
"""Get the safety_mode params"""
|
||||
return self._safety_mode
|
||||
|
||||
@property
|
||||
def max_on_percent(self):
|
||||
"""Get the max_open_percent params"""
|
||||
return self._max_on_percent
|
||||
|
||||
@property
|
||||
def central_boiler_entity(self):
|
||||
"""Get the central boiler binary_sensor entity"""
|
||||
|
||||
Reference in New Issue
Block a user