Compare commits

...

13 Commits

Author SHA1 Message Date
Maxwell Gonsalves 53dce224cd Change VTherm temperature unit to HA's preferred unit. (#461)
* Change VTherm temperature unit to HA's preferred unit.

* fix pytest issue

* update current_temperature, explicitly convert temps (fixes pytest error)
2024-06-10 18:46:45 +02:00
Jean-Marc Collin 2fd60074c7 Beers ! 2024-05-28 08:47:14 +02:00
jkreiss-coexya 549423b313 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
2024-05-13 08:27:52 +02:00
Matt Bush 6bd1b1137e [Draft] Use user's preferred temperature unit instead of hardcoding celsius (#460)
* Use user's preferred temperature unit instead of hardcoding celsius

* Fix warnings about using is instead of == in tests
2024-05-13 07:47:04 +02:00
Jean-Marc Collin 189418e69a Beers 2024-05-11 10:47:33 +02:00
Jean-Marc Collin 4ab932f44e Update README-fr.md
Beers !
2024-05-11 10:46:59 +02:00
misa1515 e1ff23fb30 Update sk.json (#454) 2024-04-29 07:15:26 +02:00
Jean-Marc Collin 7b657ffabf Issue 444 ha 2024.04.3 (#452)
* HA 2024.4.3 and release

* [#444] - fix initial temp values with standalone presets

---------

Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com>
2024-04-23 07:58:22 +02:00
Jean-Marc Collin acd22d1fc4 HA 2024.4.3 and release (#447)
Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com>
2024-04-16 08:54:59 +02:00
Jean-Marc Collin d6f33d5796 [#438] - manage total_energy none until restored or calculated (#446)
Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com>
2024-04-16 07:14:38 +02:00
Jean-Marc Collin c1ebb46ac6 [#358] - Block preset_mode change on central_mode status (#445)
Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com>
2024-04-15 08:06:07 +02:00
Jean-Marc Collin eee4a9c4e3 Beers ! 2024-04-08 05:33:56 +00:00
Jean-Marc Collin 2a3d3ff877 [#429] - VTherm doesn't respect target temperature (#435)
Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com>
2024-04-01 12:34:18 +02:00
19 changed files with 466 additions and 180 deletions
+10 -5
View File
@@ -3,10 +3,12 @@ default_config:
logger: logger:
default: warning default: warning
logs: logs:
custom_components.versatile_thermostat: info custom_components.versatile_thermostat: debug
custom_components.versatile_thermostat.underlyings: info # custom_components.versatile_thermostat.underlyings: info
custom_components.versatile_thermostat.climate: info # custom_components.versatile_thermostat.climate: info
custom_components.versatile_thermostat.base_thermostat: debug # custom_components.versatile_thermostat.base_thermostat: debug
custom_components.versatile_thermostat.sensor: info
custom_components.versatile_thermostat.binary_sensor: info
# If you need to debug uncommment the line below (doc: https://www.home-assistant.io/integrations/debugpy/) # If you need to debug uncommment the line below (doc: https://www.home-assistant.io/integrations/debugpy/)
debugpy: debugpy:
@@ -175,7 +177,7 @@ input_datetime:
has_time: true has_time: true
recorder: recorder:
commit_interval: 1 commit_interval: 0
include: include:
domains: domains:
- input_boolean - input_boolean
@@ -184,6 +186,9 @@ recorder:
- climate - climate
- sensor - sensor
- binary_sensor - binary_sensor
- number
- input_select
- versatile_thermostat
template: template:
- binary_sensor: - binary_sensor:
+1 -1
View File
@@ -212,7 +212,7 @@ En conséquence toute la phase de paramètrage d'un VTherm a été profondemment
</details> </details>
# Merci pour la bière [buymecoffee](https://www.buymeacoffee.com/jmcollin78) # Merci pour la bière [buymecoffee](https://www.buymeacoffee.com/jmcollin78)
Un grand merci à @salabur, @pvince83, @bergoglio, @EPicLURcher, @ecolorado66, @Kriss1670, @maia, @f.maymil, @moutte69, @Jerome, @Gunnar M, @Greg.o, @John Burgess, @abyssmal, @capinfo26, @Helge, @MattG @Mexx62, @Someone, @Lajull, @giopeco, @fredericselier, @philpagan, @studiogriffanti, @Edwin, @Sebbou, @Gerard R. pour les bières. Ca fait très plaisir et ça m'encourage à continuer ! Un grand merci à @salabur, @pvince83, @bergoglio, @EPicLURcher, @ecolorado66, @Kriss1670, @maia, @f.maymil, @moutte69, @Jerome, @Gunnar M, @Greg.o, @John Burgess, @abyssmal, @capinfo26, @Helge, @MattG @Mexx62, @Someone, @Lajull, @giopeco, @fredericselier, @philpagan, @studiogriffanti, @Edwin, @Sebbou, @Gerard R., @John Burgess, @Sylvoliv, @cdenfert, @stephane.l, @jms92100 pour les bières. Ca fait très plaisir et ça m'encourage à continuer !
# Quand l'utiliser et ne pas l'utiliser # Quand l'utiliser et ne pas l'utiliser
+1 -1
View File
@@ -213,7 +213,7 @@ Consequently, the entire configuration phase of a VTherm has been profoundly mod
</details> </details>
# Thanks for the beer [buymecoffee](https://www.buymeacoffee.com/jmcollin78) # Thanks for the beer [buymecoffee](https://www.buymeacoffee.com/jmcollin78)
Many thanks to @salabur, @pvince83, @bergoglio, @EPicLURcher, @ecolorado66, @Kriss1670, @maia, @f.maymil, @moutte69, @Jerome, @Gunnar M, @Greg.o, @John Burgess, @abyssmal, @capinfo26, @Helge, @MattG, @MattG, @Mexx62, @Someone, @Lajull, @giopeco, @fredericselier, @philpagan, @studiogriffanti, @Edwin, @Sebbou, @Gerard R. for the beers. It's very nice and encourages me to continue! Many thanks to @salabur, @pvince83, @bergoglio, @EPicLURcher, @ecolorado66, @Kriss1670, @maia, @f.maymil, @moutte69, @Jerome, @Gunnar M, @Greg.o, @John Burgess, @abyssmal, @capinfo26, @Helge, @MattG, @MattG, @Mexx62, @Someone, @Lajull, @giopeco, @fredericselier, @philpagan, @studiogriffanti, @Edwin, @Sebbou, @Gerard R., @John Burgess, @Sylvoliv, @cdenfert, @stephane.l, @jms92100 for the beers. It's very nice and encourages me to continue!
# When to use / not use # When to use / not use
This thermostat can control 3 types of equipment: This thermostat can control 3 types of equipment:
@@ -532,7 +532,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
self._overpowering_state = None self._overpowering_state = None
self._presence_state = None self._presence_state = None
self._total_energy = 0 self._total_energy = None
# Read the parameter from configuration.yaml if it exists # Read the parameter from configuration.yaml if it exists
short_ema_params = DEFAULT_SHORT_EMA_PARAMS short_ema_params = DEFAULT_SHORT_EMA_PARAMS
@@ -860,8 +860,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
self._hvac_mode = HVACMode.OFF self._hvac_mode = HVACMode.OFF
old_total_energy = old_state.attributes.get(ATTR_TOTAL_ENERGY) old_total_energy = old_state.attributes.get(ATTR_TOTAL_ENERGY)
if old_total_energy: self._total_energy = old_total_energy if old_total_energy else 0
self._total_energy = old_total_energy
self.restore_specific_previous_state(old_state) self.restore_specific_previous_state(old_state)
else: else:
@@ -874,6 +873,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
_LOGGER.warning( _LOGGER.warning(
"No previously saved temperature, setting to %s", self._target_temp "No previously saved temperature, setting to %s", self._target_temp
) )
self._total_energy = 0
self._saved_target_temp = self._target_temp self._saved_target_temp = self._target_temp
@@ -1063,7 +1063,10 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
@property @property
def total_energy(self) -> float | None: def total_energy(self) -> float | None:
"""Returns the total energy calculated for this thermostast""" """Returns the total energy calculated for this thermostast"""
return round(self._total_energy, 2) if self._total_energy is not None:
return round(self._total_energy, 2)
else:
return None
@property @property
def device_power(self) -> float | None: def device_power(self) -> float | None:
@@ -1258,6 +1261,31 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
self, preset_mode: str, overwrite_saved_preset=True self, preset_mode: str, overwrite_saved_preset=True
): ):
"""Set new preset mode.""" """Set new preset mode."""
# Wer accept a new preset when:
# 1. last_central_mode is not set,
# 2. or last_central_mode is AUTO,
# 3. or last_central_mode is CENTRAL_MODE_FROST_PROTECTION and preset_mode is PRESET_FROST_PROTECTION (to be abel to re-set the preset_mode)
accept = self._last_central_mode in [
None,
CENTRAL_MODE_AUTO,
CENTRAL_MODE_COOL_ONLY,
CENTRAL_MODE_HEAT_ONLY,
CENTRAL_MODE_STOPPED,
] or (
self._last_central_mode == CENTRAL_MODE_FROST_PROTECTION
and preset_mode == PRESET_FROST_PROTECTION
)
if not accept:
_LOGGER.info(
"%s - Impossible to change the preset to %s because central mode is %s",
self,
preset_mode,
self._last_central_mode,
)
return
await self._async_set_preset_mode_internal( await self._async_set_preset_mode_internal(
preset_mode, force=False, overwrite_saved_preset=overwrite_saved_preset preset_mode, force=False, overwrite_saved_preset=overwrite_saved_preset
) )
@@ -2302,12 +2330,12 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
self._security_state = True self._security_state = True
self.save_hvac_mode() self.save_hvac_mode()
self.save_preset_mode() self.save_preset_mode()
if self._prop_algorithm:
self._prop_algorithm.set_security(self._security_default_on_percent)
await self._async_set_preset_mode_internal(PRESET_SECURITY) await self._async_set_preset_mode_internal(PRESET_SECURITY)
# Turn off the underlying climate or heater if security default on_percent is 0 # Turn off the underlying climate or heater if security default on_percent is 0
if self.is_over_climate or self._security_default_on_percent <= 0.0: if self.is_over_climate or self._security_default_on_percent <= 0.0:
await self.async_set_hvac_mode(HVACMode.OFF, False) await self.async_set_hvac_mode(HVACMode.OFF, False)
if self._prop_algorithm:
self._prop_algorithm.set_security(self._security_default_on_percent)
self.send_event( self.send_event(
EventType.SECURITY_EVENT, EventType.SECURITY_EVENT,
@@ -2334,12 +2362,12 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
self._saved_preset_mode, self._saved_preset_mode,
) )
self._security_state = False self._security_state = False
if self._prop_algorithm:
self._prop_algorithm.unset_security()
# Restore hvac_mode if previously saved # Restore hvac_mode if previously saved
if self.is_over_climate or self._security_default_on_percent <= 0.0: if self.is_over_climate or self._security_default_on_percent <= 0.0:
await self.restore_hvac_mode(False) await self.restore_hvac_mode(False)
await self.restore_preset_mode() await self.restore_preset_mode()
if self._prop_algorithm:
self._prop_algorithm.unset_security()
self.send_event( self.send_event(
EventType.SECURITY_EVENT, EventType.SECURITY_EVENT,
{ {
@@ -2569,7 +2597,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
"""update the entity if the config entry have been updated """update the entity if the config entry have been updated
Note: this don't work either Note: this don't work either
""" """
_LOGGER.info("%s - The config entry have been updated") _LOGGER.info("%s - The config entry have been updated", self)
async def service_set_presence(self, presence: str): async def service_set_presence(self, presence: str):
"""Called by a service call: """Called by a service call:
@@ -14,6 +14,6 @@
"quality_scale": "silver", "quality_scale": "silver",
"requirements": [], "requirements": [],
"ssdp": [], "ssdp": [],
"version": "6.2.0", "version": "6.2.3",
"zeroconf": [] "zeroconf": []
} }
@@ -11,6 +11,9 @@ from homeassistant.components.number import (
NumberMode, NumberMode,
NumberDeviceClass, NumberDeviceClass,
DOMAIN as NUMBER_DOMAIN, DOMAIN as NUMBER_DOMAIN,
DEFAULT_MAX_VALUE,
DEFAULT_MIN_VALUE,
DEFAULT_STEP,
) )
from homeassistant.components.climate import ( from homeassistant.components.climate import (
PRESET_BOOST, PRESET_BOOST,
@@ -53,6 +56,7 @@ from .const import (
CONF_USE_PRESENCE_FEATURE, CONF_USE_PRESENCE_FEATURE,
CONF_USE_CENTRAL_BOILER_FEATURE, CONF_USE_CENTRAL_BOILER_FEATURE,
overrides, overrides,
CONF_USE_MAIN_CENTRAL_CONFIG,
) )
PRESET_ICON_MAPPING = { PRESET_ICON_MAPPING = {
@@ -279,7 +283,7 @@ class CentralConfigTemperatureNumber(
self.entity_id = f"{NUMBER_DOMAIN}.{slugify(name)}_preset_{preset_name}" self.entity_id = f"{NUMBER_DOMAIN}.{slugify(name)}_preset_{preset_name}"
self._attr_unique_id = f"central_configuration_preset_{preset_name}" self._attr_unique_id = f"central_configuration_preset_{preset_name}"
self._attr_device_class = NumberDeviceClass.TEMPERATURE self._attr_device_class = NumberDeviceClass.TEMPERATURE
self._attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS self._attr_native_unit_of_measurement = hass.config.units.temperature_unit
self._attr_native_step = entry_infos.get(CONF_STEP_TEMPERATURE, 0.5) self._attr_native_step = entry_infos.get(CONF_STEP_TEMPERATURE, 0.5)
self._attr_native_min_value = entry_infos.get(CONF_TEMP_MIN) self._attr_native_min_value = entry_infos.get(CONF_TEMP_MIN)
@@ -341,7 +345,10 @@ class CentralConfigTemperatureNumber(
async def async_set_native_value(self, value: float) -> None: async def async_set_native_value(self, value: float) -> None:
"""The value have change from the Number Entity in UI""" """The value have change from the Number Entity in UI"""
float_value = float(value) float_value = float(value)
old_value = float(self._attr_native_value) old_value = (
None if self._attr_native_value is None else float(self._attr_native_value)
)
if float_value == old_value: if float_value == old_value:
return return
@@ -364,7 +371,7 @@ class CentralConfigTemperatureNumber(
# TODO Kelvin ? It seems not because all internal values are stored in # TODO Kelvin ? It seems not because all internal values are stored in
# ° Celsius but only the render in front can be in °K depending on the # ° Celsius but only the render in front can be in °K depending on the
# user configuration. # user configuration.
return UnitOfTemperature.CELSIUS return self.hass.config.units.temperature_unit
class TemperatureNumber( # pylint: disable=abstract-method class TemperatureNumber( # pylint: disable=abstract-method
@@ -393,11 +400,13 @@ class TemperatureNumber( # pylint: disable=abstract-method
self._attr_unique_id = f"{self._device_name}_preset_{preset_name}" self._attr_unique_id = f"{self._device_name}_preset_{preset_name}"
self._attr_device_class = NumberDeviceClass.TEMPERATURE self._attr_device_class = NumberDeviceClass.TEMPERATURE
self._attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS self._attr_native_unit_of_measurement = hass.config.units.temperature_unit
self._attr_native_step = entry_infos.get(CONF_STEP_TEMPERATURE, 0.5) self._has_central_main_attributes = entry_infos.get(
self._attr_native_min_value = entry_infos.get(CONF_TEMP_MIN) CONF_USE_MAIN_CENTRAL_CONFIG, False
self._attr_native_max_value = entry_infos.get(CONF_TEMP_MAX) )
self.init_min_max_step(entry_infos)
# Initialize the values if included into the entry_infos. This will do # Initialize the values if included into the entry_infos. This will do
# the temperature migration. # the temperature migration.
@@ -459,7 +468,9 @@ class TemperatureNumber( # pylint: disable=abstract-method
return return
float_value = float(value) float_value = float(value)
old_value = float(self._attr_native_value) old_value = (
None if self._attr_native_value is None else float(self._attr_native_value)
)
if float_value == old_value: if float_value == old_value:
return return
@@ -476,6 +487,10 @@ class TemperatureNumber( # pylint: disable=abstract-method
) )
) )
# We set the min, max and step from central config if relevant because it is possible that central config
# was not loaded at startup
self.init_min_max_step()
def __str__(self): def __str__(self):
return f"VersatileThermostat-{self.name}" return f"VersatileThermostat-{self.name}"
@@ -483,5 +498,28 @@ class TemperatureNumber( # pylint: disable=abstract-method
def native_unit_of_measurement(self) -> str | None: def native_unit_of_measurement(self) -> str | None:
"""The unit of measurement""" """The unit of measurement"""
if not self.my_climate: if not self.my_climate:
return UnitOfTemperature.CELSIUS return self.hass.config.units.temperature_unit
return self.my_climate.temperature_unit return self.my_climate.temperature_unit
def init_min_max_step(self, entry_infos=None):
"""Initialize min, max and step value from config or from central config"""
if self._has_central_main_attributes:
vthermapi: VersatileThermostatAPI = VersatileThermostatAPI.get_vtherm_api()
central_config = vthermapi.find_central_configuration()
if central_config:
self._attr_native_step = central_config.data.get(CONF_STEP_TEMPERATURE)
self._attr_native_min_value = central_config.data.get(CONF_TEMP_MIN)
self._attr_native_max_value = central_config.data.get(CONF_TEMP_MAX)
return
if entry_infos:
self._attr_native_step = entry_infos.get(
CONF_STEP_TEMPERATURE, DEFAULT_STEP
)
self._attr_native_min_value = entry_infos.get(
CONF_TEMP_MIN, DEFAULT_MIN_VALUE
)
self._attr_native_max_value = entry_infos.get(
CONF_TEMP_MAX, DEFAULT_MAX_VALUE
)
@@ -24,16 +24,19 @@ class PropAlgorithm:
tpi_coef_ext, tpi_coef_ext,
cycle_min: int, cycle_min: int,
minimal_activation_delay: int, minimal_activation_delay: int,
vtherm_entity_id: str = None,
) -> None: ) -> None:
"""Initialisation of the Proportional Algorithm""" """Initialisation of the Proportional Algorithm"""
_LOGGER.debug( _LOGGER.debug(
"Creation new PropAlgorithm function_type: %s, tpi_coef_int: %s, tpi_coef_ext: %s, cycle_min:%d, minimal_activation_delay:%d", # pylint: disable=line-too-long "%s - Creation new PropAlgorithm function_type: %s, tpi_coef_int: %s, tpi_coef_ext: %s, cycle_min:%d, minimal_activation_delay:%d", # pylint: disable=line-too-long
vtherm_entity_id,
function_type, function_type,
tpi_coef_int, tpi_coef_int,
tpi_coef_ext, tpi_coef_ext,
cycle_min, cycle_min,
minimal_activation_delay, minimal_activation_delay,
) )
self._vtherm_entity_id = vtherm_entity_id
self._function = function_type self._function = function_type
self._tpi_coef_int = tpi_coef_int self._tpi_coef_int = tpi_coef_int
self._tpi_coef_ext = tpi_coef_ext self._tpi_coef_ext = tpi_coef_ext
@@ -57,7 +60,10 @@ class PropAlgorithm:
if target_temp is None or current_temp is None: if target_temp is None or current_temp is None:
log = _LOGGER.debug if hvac_mode == HVACMode.OFF else _LOGGER.warning log = _LOGGER.debug if hvac_mode == HVACMode.OFF else _LOGGER.warning
log( log(
"Proportional algorithm: calculation is not possible cause target_temp or current_temp is null. Heating/cooling will be disabled" # pylint: disable=line-too-long "%s - Proportional algorithm: calculation is not possible cause target_temp (%s) or current_temp (%s) is null. Heating/cooling will be disabled. This could be normal at startup", # pylint: disable=line-too-long
self._vtherm_entity_id,
target_temp,
current_temp,
) )
self._calculated_on_percent = 0 self._calculated_on_percent = 0
else: else:
@@ -83,7 +89,8 @@ class PropAlgorithm:
) )
else: else:
_LOGGER.warning( _LOGGER.warning(
"Proportional algorithm: unknown %s function. Heating will be disabled", "%s - Proportional algorithm: unknown %s function. Heating will be disabled",
self._vtherm_entity_id,
self._function, self._function,
) )
self._calculated_on_percent = 0 self._calculated_on_percent = 0
@@ -91,7 +98,8 @@ class PropAlgorithm:
self._calculate_internal() self._calculate_internal()
_LOGGER.debug( _LOGGER.debug(
"heating percent calculated for current_temp %.1f, ext_current_temp %.1f and target_temp %.1f is %.2f, on_time is %d (sec), off_time is %d (sec)", # pylint: disable=line-too-long "%s - heating percent calculated for current_temp %.1f, ext_current_temp %.1f and target_temp %.1f is %.2f, on_time is %d (sec), off_time is %d (sec)", # pylint: disable=line-too-long
self._vtherm_entity_id,
current_temp if current_temp else -9999.0, current_temp if current_temp else -9999.0,
ext_current_temp if ext_current_temp else -9999.0, ext_current_temp if ext_current_temp else -9999.0,
target_temp if target_temp else -9999.0, target_temp if target_temp else -9999.0,
@@ -110,11 +118,12 @@ class PropAlgorithm:
self._calculated_on_percent = 0 self._calculated_on_percent = 0
if self._security: if self._security:
_LOGGER.debug(
"Security is On using the default_on_percent %f",
self._default_on_percent,
)
self._on_percent = self._default_on_percent self._on_percent = self._default_on_percent
_LOGGER.info(
"%s - Security is On using the default_on_percent %f",
self._vtherm_entity_id,
self._on_percent,
)
else: else:
_LOGGER.debug( _LOGGER.debug(
"Security is Off using the calculated_on_percent %f", "Security is Off using the calculated_on_percent %f",
@@ -128,13 +137,8 @@ class PropAlgorithm:
if self._on_time_sec < self._minimal_activation_delay: if self._on_time_sec < self._minimal_activation_delay:
if self._on_time_sec > 0: if self._on_time_sec > 0:
_LOGGER.info( _LOGGER.info(
"No heating period due to heating period too small (%f < %f)", "%s - No heating period due to heating period too small (%f < %f)",
self._on_time_sec, self._vtherm_entity_id,
self._minimal_activation_delay,
)
else:
_LOGGER.debug(
"No heating period due to heating period too small (%f < %f)",
self._on_time_sec, self._on_time_sec,
self._minimal_activation_delay, self._minimal_activation_delay,
) )
@@ -144,12 +148,18 @@ class PropAlgorithm:
def set_security(self, default_on_percent: float): def set_security(self, default_on_percent: float):
"""Set a default value for on_percent (used for safety mode)""" """Set a default value for on_percent (used for safety mode)"""
_LOGGER.info(
"%s - Proportional Algo - set security to ON", self._vtherm_entity_id
)
self._security = True self._security = True
self._default_on_percent = default_on_percent self._default_on_percent = default_on_percent
self._calculate_internal() self._calculate_internal()
def unset_security(self): def unset_security(self):
"""Unset the safety mode""" """Unset the safety mode"""
_LOGGER.info(
"%s - Proportional Algo - set security to OFF", self._vtherm_entity_id
)
self._security = False self._security = False
self._calculate_internal() self._calculate_internal()
@@ -125,15 +125,15 @@ class EnergySensor(VersatileThermostatBaseEntity, SensorEntity):
"""Called when my climate have change""" """Called when my climate have change"""
_LOGGER.debug("%s - climate state change", self._attr_unique_id) _LOGGER.debug("%s - climate state change", self._attr_unique_id)
if math.isnan(self.my_climate.total_energy) or math.isinf( energy = self.my_climate.total_energy
self.my_climate.total_energy if energy is None:
): return
if math.isnan(energy) or math.isinf(energy):
raise ValueError(f"Sensor has illegal state {self.my_climate.total_energy}") raise ValueError(f"Sensor has illegal state {self.my_climate.total_energy}")
old_state = self._attr_native_value old_state = self._attr_native_value
self._attr_native_value = round( self._attr_native_value = round(energy, self.suggested_display_precision)
self.my_climate.total_energy, self.suggested_display_precision
)
if old_state != self._attr_native_value: if old_state != self._attr_native_value:
self.async_write_ha_state() self.async_write_ha_state()
return return
@@ -570,7 +570,7 @@ class RegulatedTemperatureSensor(VersatileThermostatBaseEntity, SensorEntity):
@property @property
def native_unit_of_measurement(self) -> str | None: def native_unit_of_measurement(self) -> str | None:
if not self.my_climate: if not self.my_climate:
return UnitOfTemperature.CELSIUS return self.hass.config.units.temperature_unit
return self.my_climate.temperature_unit return self.my_climate.temperature_unit
@property @property
@@ -621,7 +621,7 @@ class EMATemperatureSensor(VersatileThermostatBaseEntity, SensorEntity):
@property @property
def native_unit_of_measurement(self) -> str | None: def native_unit_of_measurement(self) -> str | None:
if not self.my_climate: if not self.my_climate:
return UnitOfTemperature.CELSIUS return self.hass.config.units.temperature_unit
return self.my_climate.temperature_unit return self.my_climate.temperature_unit
@property @property
@@ -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",
@@ -581,7 +587,11 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
): ):
added_energy = self._device_power * self._underlying_climate_delta_t added_energy = self._device_power * self._underlying_climate_delta_t
self._total_energy += added_energy if self._total_energy is None:
self._total_energy = added_energy
else:
self._total_energy += added_energy
_LOGGER.debug( _LOGGER.debug(
"%s - added energy is %.3f . Total energy is now: %.3f", "%s - added energy is %.3f . Total energy is now: %.3f",
self, self,
@@ -890,10 +900,7 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
@property @property
def temperature_unit(self) -> str: def temperature_unit(self) -> str:
"""Return the unit of measurement.""" """Return the unit of measurement."""
if self.underlying_entity(0): return self.hass.config.units.temperature_unit
return self.underlying_entity(0).temperature_unit
return self._unit
@property @property
def supported_features(self): def supported_features(self):
@@ -88,6 +88,7 @@ class ThermostatOverSwitch(BaseThermostat[UnderlyingSwitch]):
self._tpi_coef_ext, self._tpi_coef_ext,
self._cycle_min, self._cycle_min,
self._minimal_activation_delay, self._minimal_activation_delay,
self.name,
) )
lst_switches = [config_entry.get(CONF_HEATER)] lst_switches = [config_entry.get(CONF_HEATER)]
@@ -198,7 +199,11 @@ class ThermostatOverSwitch(BaseThermostat[UnderlyingSwitch]):
if not self.is_over_climate and self.mean_cycle_power is not None: if not self.is_over_climate and self.mean_cycle_power is not None:
added_energy = self.mean_cycle_power * float(self._cycle_min) / 60.0 added_energy = self.mean_cycle_power * float(self._cycle_min) / 60.0
self._total_energy += added_energy if self._total_energy is None:
self._total_energy = added_energy
else:
self._total_energy += added_energy
_LOGGER.debug( _LOGGER.debug(
"%s - added energy is %.3f . Total energy is now: %.3f", "%s - added energy is %.3f . Total energy is now: %.3f",
self, self,
@@ -105,6 +105,7 @@ class ThermostatOverValve(BaseThermostat[UnderlyingValve]): # pylint: disable=a
self._tpi_coef_ext, self._tpi_coef_ext,
self._cycle_min, self._cycle_min,
self._minimal_activation_delay, self._minimal_activation_delay,
self.name,
) )
lst_valves = [config_entry.get(CONF_VALVE)] lst_valves = [config_entry.get(CONF_VALVE)]
@@ -278,7 +279,11 @@ class ThermostatOverValve(BaseThermostat[UnderlyingValve]): # pylint: disable=a
if not self.is_over_climate and self.mean_cycle_power is not None: if not self.is_over_climate and self.mean_cycle_power is not None:
added_energy = self.mean_cycle_power * float(self._cycle_min) / 60.0 added_energy = self.mean_cycle_power * float(self._cycle_min) / 60.0
self._total_energy += added_energy if self._total_energy is None:
self._total_energy = added_energy
else:
self._total_energy += added_energy
_LOGGER.debug( _LOGGER.debug(
"%s - added energy is %.3f . Total energy is now: %.3f", "%s - added energy is %.3f . Total energy is now: %.3f",
self, self,
@@ -12,6 +12,25 @@
"thermostat_type": "Len jeden centrálny typ konfigurácie je možný" "thermostat_type": "Len jeden centrálny typ konfigurácie je možný"
} }
}, },
"menu": {
"title": "Menu",
"description": "Nakonfigurujte si termostat. Po zadaní všetkých požadovaných parametrov budete môcť dokončiť konfiguráciu.",
"menu_options": {
"main": "Hlavné atribúty",
"central_boiler": "Centrálny kotol",
"type": "Podklady",
"tpi": "TPI parametre",
"features": "Vlastnosti",
"presets": "Predvoľby",
"window": "Detekcia okien",
"motion": "Detekcia pohybu",
"power": "Správa napájania",
"presence": "Detekcia prítomnosti",
"advanced": "Pokročilé parametre",
"finalize": "Všetko hotové",
"configuration_not_complete": "Konfigurácia nie je dokončená"
}
},
"main": { "main": {
"title": "Pridajte nový všestranný termostat", "title": "Pridajte nový všestranný termostat",
"description": "Hlavné povinné atribúty", "description": "Hlavné povinné atribúty",
@@ -19,22 +38,32 @@
"name": "Názov", "name": "Názov",
"thermostat_type": "Termostat typ", "thermostat_type": "Termostat typ",
"temperature_sensor_entity_id": "ID entity snímača teploty", "temperature_sensor_entity_id": "ID entity snímača teploty",
"last_seen_temperature_sensor_entity_id": "Dátum posledného zobrazenia izbovej teploty",
"external_temperature_sensor_entity_id": "ID entity externého snímača teploty", "external_temperature_sensor_entity_id": "ID entity externého snímača teploty",
"cycle_min": "Trvanie cyklu (minúty)", "cycle_min": "Trvanie cyklu (minúty)",
"temp_min": "Minimálna povolená teplota", "temp_min": "Minimálna povolená teplota",
"temp_max": "Maximálna povolená teplota", "temp_max": "Maximálna povolená teplota",
"step_temperature": "Krok teploty",
"device_power": "Napájanie zariadenia", "device_power": "Napájanie zariadenia",
"use_central_mode": "Povoliť ovládanie centrálnou entitou (potrebná centrálna konfigurácia)", "use_central_mode": "Povoliť ovládanie centrálnou entitou (potrebná centrálna konfigurácia)",
"use_main_central_config": "Použite dodatočnú centrálnu hlavnú konfiguráciu. Začiarknite, ak chcete použiť centrálnu hlavnú konfiguráciu (vonkajšia teplota, min, max, krok, ...).",
"used_by_controls_central_boiler": "Používa sa centrálnym kotlom. Skontrolujte, či má mať tento VTherm ovládanie na centrálnom kotli"
},
"data_description": {
"temperature_sensor_entity_id": "ID entity snímača izbovej teploty",
"last_seen_temperature_sensor_entity_id": "Naposledy videný snímač izbovej teploty ID entity. Mal by to byť snímač dátumu a času",
"external_temperature_sensor_entity_id": "ID entity snímača vonkajšej teploty. Nepoužíva sa, ak je zvolená centrálna konfigurácia"
}
},
"features": {
"title": "Vlastnosti",
"description": "Vlastnosti termostatu",
"data": {
"use_window_feature": "Použite detekciu okien", "use_window_feature": "Použite detekciu okien",
"use_motion_feature": "Použite detekciu pohybu", "use_motion_feature": "Použite detekciu pohybu",
"use_power_feature": "Použite správu napájania", "use_power_feature": "Použite správu napájania",
"use_presence_feature": "Použite detekciu prítomnosti", "use_presence_feature": "Použite detekciu prítomnosti",
"use_main_central_config": "Použite centrálnu hlavnú konfiguráciu" "use_central_boiler_feature": "Použite centrálny kotol. Začiarknutím tohto políčka pridáte ovládanie do centrálneho kotla. Po zaškrtnutí tohto políčka budete musieť nakonfigurovať VTherm, ktorý bude mať ovládanie centrálneho kotla, aby sa prejavilo. Ak jeden VTherm vyžaduje ohrev, kotol sa zapne. Ak žiadny VTherm nevyžaduje ohrev, kotol sa vypne. Príkazy na zapnutie/vypnutie centrálneho kotla sú uvedené na príslušnej konfiguračnej stránke"
},
"data_description": {
"use_central_mode": "Zaškrtnutím povolíte ovládanie VTherm pomocou vybraných entít central_mode",
"use_main_central_config": "Začiarknite, ak chcete použiť centrálnu hlavnú konfiguráciu. Zrušte začiarknutie, ak chcete použiť špecifickú hlavnú konfiguráciu pre tento VTherm",
"external_temperature_sensor_entity_id": "ID entity snímača vonkajšej teploty. Nepoužíva sa, ak je zvolená centrálna konfigurácia"
} }
}, },
"type": { "type": {
@@ -45,6 +74,7 @@
"heater_entity2_id": "2. spínač ohrievača", "heater_entity2_id": "2. spínač ohrievača",
"heater_entity3_id": "3. spínač ohrievača", "heater_entity3_id": "3. spínač ohrievača",
"heater_entity4_id": "4. spínač ohrievača", "heater_entity4_id": "4. spínač ohrievača",
"heater_keep_alive": "Prepnite interval udržiavania v sekundách",
"proportional_function": "Algoritmus", "proportional_function": "Algoritmus",
"climate_entity_id": "1. základná klíma", "climate_entity_id": "1. základná klíma",
"climate_entity2_id": "2. základná klíma", "climate_entity2_id": "2. základná klíma",
@@ -58,6 +88,7 @@
"auto_regulation_mode": "Samoregulácia", "auto_regulation_mode": "Samoregulácia",
"auto_regulation_dtemp": "Regulačný prah", "auto_regulation_dtemp": "Regulačný prah",
"auto_regulation_periode_min": "Regulačné minimálne obdobie", "auto_regulation_periode_min": "Regulačné minimálne obdobie",
"auto_regulation_use_device_temp": "Použite vnútornú teplotu podkladu",
"inverse_switch_command": "Inverzný prepínací príkaz", "inverse_switch_command": "Inverzný prepínací príkaz",
"auto_fan_mode": "Režim automatického ventilátora" "auto_fan_mode": "Režim automatického ventilátora"
}, },
@@ -66,6 +97,7 @@
"heater_entity2_id": "Voliteľné ID entity 2. ohrievača. Ak sa nepoužíva, nechajte prázdne", "heater_entity2_id": "Voliteľné ID entity 2. ohrievača. Ak sa nepoužíva, nechajte prázdne",
"heater_entity3_id": "Voliteľné ID entity 3. ohrievača. Ak sa nepoužíva, nechajte prázdne", "heater_entity3_id": "Voliteľné ID entity 3. ohrievača. Ak sa nepoužíva, nechajte prázdne",
"heater_entity4_id": "Voliteľné ID entity 4. ohrievača. Ak sa nepoužíva, nechajte prázdne", "heater_entity4_id": "Voliteľné ID entity 4. ohrievača. Ak sa nepoužíva, nechajte prázdne",
"heater_keep_alive": "Voliteľný interval obnovy stavu spínača ohrievača. Ak to nie je potrebné, nechajte prázdne.",
"proportional_function": "Algoritmus, ktorý sa má použiť (TPI je zatiaľ jediný)", "proportional_function": "Algoritmus, ktorý sa má použiť (TPI je zatiaľ jediný)",
"climate_entity_id": "ID základnej klimatickej entity", "climate_entity_id": "ID základnej klimatickej entity",
"climate_entity2_id": "2. základné identifikačné číslo klimatickej entity", "climate_entity2_id": "2. základné identifikačné číslo klimatickej entity",
@@ -79,6 +111,7 @@
"auto_regulation_mode": "Automatické nastavenie cieľovej teploty", "auto_regulation_mode": "Automatické nastavenie cieľovej teploty",
"auto_regulation_dtemp": "Hranica v °, pod ktorou sa zmena teploty neodošle", "auto_regulation_dtemp": "Hranica v °, pod ktorou sa zmena teploty neodošle",
"auto_regulation_periode_min": "Trvanie v minútach medzi dvoma aktualizáciami predpisov", "auto_regulation_periode_min": "Trvanie v minútach medzi dvoma aktualizáciami predpisov",
"auto_regulation_use_device_temp": "Na urýchlenie samoregulácie použite prípadný vnútorný snímač teploty podkladu",
"inverse_switch_command": "V prípade spínača s pilotným vodičom a diódou možno budete musieť príkaz invertovať", "inverse_switch_command": "V prípade spínača s pilotným vodičom a diódou možno budete musieť príkaz invertovať",
"auto_fan_mode": "Automaticky aktivujte ventilátor, keď je potrebné veľké vykurovanie/chladenie" "auto_fan_mode": "Automaticky aktivujte ventilátor, keď je potrebné veľké vykurovanie/chladenie"
} }
@@ -101,24 +134,7 @@
"title": "Predvoľby", "title": "Predvoľby",
"description": "Pre každú predvoľbu zadajte cieľovú teplotu (0, ak chcete predvoľbu ignorovať)", "description": "Pre každú predvoľbu zadajte cieľovú teplotu (0, ak chcete predvoľbu ignorovať)",
"data": { "data": {
"eco_temp": "Teplota v predvoľbe Eco",
"comfort_temp": "Prednastavená teplota v komfortnom režime",
"boost_temp": "Teplota v prednastavení Boost",
"frost_temp": "Teplota v prednastavení Frost protection",
"eco_ac_temp": "Teplota v režime Eco prednastavená pre režim AC",
"comfort_ac_temp": "Teplota v režime Comfort je prednastavená pre režim AC",
"boost_ac_temp": "Prednastavená teplota v režime Boost pre režim AC",
"use_presets_central_config": "Použite konfiguráciu centrálnych predvolieb" "use_presets_central_config": "Použite konfiguráciu centrálnych predvolieb"
},
"data_description": {
"eco_temp": "Teplota v predvoľbe Eco",
"comfort_temp": "Prednastavená teplota v komfortnom režime",
"boost_temp": "Teplota v prednastavení Boost",
"frost_temp": "Teplota v prednastavenej ochrane proti mrazu",
"eco_ac_temp": "Teplota v režime Eco prednastavená pre režim AC",
"comfort_ac_temp": "Teplota v režime Comfort je prednastavená pre režim AC",
"boost_ac_temp": "Prednastavená teplota v režime Boost pre režim AC",
"use_presets_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálnych predvolieb. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu predvolieb pre tento VTherm"
} }
}, },
"window": { "window": {
@@ -130,7 +146,8 @@
"window_auto_open_threshold": "Prah poklesu teploty pre automatickú detekciu otvoreného okna (v °/hodina)", "window_auto_open_threshold": "Prah poklesu teploty pre automatickú detekciu otvoreného okna (v °/hodina)",
"window_auto_close_threshold": "Prahová hodnota zvýšenia teploty pre koniec automatickej detekcie (v °/hodina)", "window_auto_close_threshold": "Prahová hodnota zvýšenia teploty pre koniec automatickej detekcie (v °/hodina)",
"window_auto_max_duration": "Maximálne trvanie automatickej detekcie otvoreného okna (v min)", "window_auto_max_duration": "Maximálne trvanie automatickej detekcie otvoreného okna (v min)",
"use_window_central_config": "Použite centrálnu konfiguráciu okna" "use_window_central_config": "Použite centrálnu konfiguráciu okna",
"window_action": "Akcia"
}, },
"data_description": { "data_description": {
"window_sensor_entity_id": "Nechajte prázdne, ak nemáte použiť žiadny okenný senzor", "window_sensor_entity_id": "Nechajte prázdne, ak nemáte použiť žiadny okenný senzor",
@@ -138,7 +155,8 @@
"window_auto_open_threshold": "Odporúčaná hodnota: medzi 3 a 10. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne", "window_auto_open_threshold": "Odporúčaná hodnota: medzi 3 a 10. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne",
"window_auto_close_threshold": "Odporúčaná hodnota: 0. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne", "window_auto_close_threshold": "Odporúčaná hodnota: 0. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne",
"window_auto_max_duration": "Odporúčaná hodnota: 60 (jedna hodina). Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne", "window_auto_max_duration": "Odporúčaná hodnota: 60 (jedna hodina). Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne",
"use_window_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálneho okna. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu okna pre tento VTherm" "use_window_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálneho okna. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu okna pre tento VTherm",
"window_action": "Akcia, ktorá sa má vykonať, ak sa okno zistí ako otvorené"
} }
}, },
"motion": { "motion": {
@@ -181,26 +199,11 @@
"title": "Riadenie prítomnosti", "title": "Riadenie prítomnosti",
"description": "Atribúty správy prítomnosti.\nPoskytuje senzor prítomnosti vášho domova (pravda, ak je niekto prítomný).\nPotom zadajte buď predvoľbu, ktorá sa má použiť, keď je senzor prítomnosti nepravdivý, alebo posun teploty, ktorý sa má použiť.\nAk je zadaná predvoľba, posun sa nepoužije.\nAk sa nepoužije, ponechajte zodpovedajúce entity_id prázdne.", "description": "Atribúty správy prítomnosti.\nPoskytuje senzor prítomnosti vášho domova (pravda, ak je niekto prítomný).\nPotom zadajte buď predvoľbu, ktorá sa má použiť, keď je senzor prítomnosti nepravdivý, alebo posun teploty, ktorý sa má použiť.\nAk je zadaná predvoľba, posun sa nepoužije.\nAk sa nepoužije, ponechajte zodpovedajúce entity_id prázdne.",
"data": { "data": {
"presence_sensor_entity_id": "ID entity senzora prítomnosti", "presence_sensor_entity_id": "Senzora prítomnosti",
"eco_away_temp": "Teplota v prednastavenej Eco, keď nie je žiadna prítomnosť", "use_presence_central_config": "Použite konfiguráciu centrálnej prítomnosti teploty. Ak chcete použiť špecifické teplotné entity, zrušte výber"
"comfort_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný",
"boost_away_temp": "Prednastavená teplota v režime Boost, keď nie je prítomný",
"frost_away_temp": "Prednastavená teplota v režime Frost protection, keď nie je prítomný",
"eco_ac_away_temp": "Teplota v prednastavenej Eco, keď nie je prítomná v režime AC",
"comfort_ac_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný v režime AC",
"boost_ac_away_temp": "Teplota v prednastavenom Boost, keď nie je prítomný v režime AC",
"use_presence_central_config": "Použite centrálnu konfiguráciu prítomnosti"
}, },
"data_description": { "data_description": {
"presence_sensor_entity_id": "ID entity senzora prítomnosti", "presence_sensor_entity_id": "ID entity senzora prítomnosti"
"eco_away_temp": "Teplota v prednastavenej Eco, keď nie je žiadna prítomnosť",
"comfort_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný",
"boost_away_temp": "Prednastavená teplota v režime Boost, keď nie je prítomný",
"frost_away_temp": "Teplota v Prednastavená ochrana pred mrazom, keď nie je prítomný",
"eco_ac_away_temp": "Teplota v prednastavenej Eco, keď nie je prítomná v režime AC",
"comfort_ac_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný v režime AC",
"boost_ac_away_temp": "Teplota v prednastavenom Boost, keď nie je prítomný v režime AC",
"use_presence_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálnej prítomnosti. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu prítomnosti pre tento VTherm"
} }
}, },
"advanced": { "advanced": {
@@ -244,6 +247,25 @@
"thermostat_type": "Je možný len jeden centrálny typ konfigurácie" "thermostat_type": "Je možný len jeden centrálny typ konfigurácie"
} }
}, },
"menu": {
"title": "Menu",
"description": "Nakonfigurujte si termostat. Po zadaní všetkých požadovaných parametrov budete môcť dokončiť konfiguráciu.",
"menu_options": {
"main": "Hlavné atribúty",
"central_boiler": "Centrálny kotol",
"type": "Podklady",
"tpi": "TPI parametre",
"features": "Vlastnosti",
"presets": "Predvoľby",
"window": "Detekcia okien",
"motion": "Detekcia pohybu",
"power": "Správa napájania",
"presence": "Detekcia prítomnosti",
"advanced": "Pokročilé parametre",
"finalize": "Všetko hotové",
"configuration_not_complete": "Konfigurácia nie je dokončená"
}
},
"main": { "main": {
"title": "Hlavný - {name}", "title": "Hlavný - {name}",
"description": "Hlavné povinné atribúty", "description": "Hlavné povinné atribúty",
@@ -251,22 +273,32 @@
"name": "Názov", "name": "Názov",
"thermostat_type": "Termostat typ", "thermostat_type": "Termostat typ",
"temperature_sensor_entity_id": "ID entity snímača teploty", "temperature_sensor_entity_id": "ID entity snímača teploty",
"last_seen_temperature_sensor_entity_id": "Dátum posledného zobrazenia izbovej teploty",
"external_temperature_sensor_entity_id": "ID entity externého snímača teploty", "external_temperature_sensor_entity_id": "ID entity externého snímača teploty",
"cycle_min": "Trvanie cyklu (minúty)", "cycle_min": "Trvanie cyklu (minúty)",
"temp_min": "Minimálna povolená teplota", "temp_min": "Minimálna povolená teplota",
"temp_max": "Maximálna povolená teplota", "temp_max": "Maximálna povolená teplota",
"step_temperature": "Krok teploty",
"device_power": "Výkon zariadenia (kW)", "device_power": "Výkon zariadenia (kW)",
"use_central_mode": "Povoliť ovládanie centrálnou entitou (potrebná centrálna konfigurácia)", "use_central_mode": "Povoliť ovládanie centrálnou entitou (vyžaduje centrálnu konfiguráciu). Zaškrtnutím povolíte ovládanie VTherm pomocou vybraných entít central_mode.",
"use_main_central_config": "Použite dodatočnú centrálnu hlavnú konfiguráciu. Začiarknite, ak chcete použiť centrálnu hlavnú konfiguráciu (vonkajšia teplota, min, max, krok, ...).",
"used_by_controls_central_boiler": "Používa sa centrálnym kotlom. Skontrolujte, či má mať tento VTherm ovládanie na centrálnom kotli"
},
"data_description": {
"temperature_sensor_entity_id": "ID entity snímača izbovej teploty",
"last_seen_temperature_sensor_entity_id": "Naposledy videný snímač izbovej teploty ID entity. Mal by to byť snímač dátumu a času",
"external_temperature_sensor_entity_id": "ID entity snímača vonkajšej teploty. Nepoužíva sa, ak je zvolená centrálna konfigurácia"
}
},
"features": {
"title": "Vlastnosti - {name}",
"description": "Vlastnosti termostatu",
"data": {
"use_window_feature": "Použite detekciu okien", "use_window_feature": "Použite detekciu okien",
"use_motion_feature": "Použite detekciu pohybu", "use_motion_feature": "Použite detekciu pohybu",
"use_power_feature": "Použite správu napájania", "use_power_feature": "Použite správu napájania",
"use_presence_feature": "Použite detekciu prítomnosti", "use_presence_feature": "Použite detekciu prítomnosti",
"use_main_central_config": "Použite centrálnu hlavnú konfiguráciu" "use_central_boiler_feature": "Použite centrálny kotol. Začiarknutím tohto políčka pridáte ovládanie do centrálneho kotla. Po zaškrtnutí tohto políčka budete musieť nakonfigurovať VTherm, ktorý bude mať ovládanie centrálneho kotla, aby sa prejavilo. Ak jeden VTherm vyžaduje ohrev, kotol sa zapne. Ak žiadny VTherm nevyžaduje ohrev, kotol sa vypne. Príkazy na zapnutie/vypnutie centrálneho kotla sú uvedené na príslušnej konfiguračnej stránke"
},
"data_description": {
"use_central_mode": "Zaškrtnutím povolíte ovládanie VTherm pomocou vybraných entít central_mode",
"use_main_central_config": "Začiarknite, ak chcete použiť centrálnu hlavnú konfiguráciu. Ak chcete použiť špecifickú konfiguráciu pre tento VTherm, zrušte začiarknutie",
"external_temperature_sensor_entity_id": "ID entity snímača vonkajšej teploty. Nepoužíva sa, ak je zvolená centrálna konfigurácia"
} }
}, },
"type": { "type": {
@@ -277,6 +309,7 @@
"heater_entity2_id": "2. spínač ohrievača", "heater_entity2_id": "2. spínač ohrievača",
"heater_entity3_id": "3. spínač ohrievača", "heater_entity3_id": "3. spínač ohrievača",
"heater_entity4_id": "4. spínač ohrievača", "heater_entity4_id": "4. spínač ohrievača",
"heater_keep_alive": "Prepnite interval udržiavania v sekundách",
"proportional_function": "Algoritmus", "proportional_function": "Algoritmus",
"climate_entity_id": "Základná klíma", "climate_entity_id": "Základná klíma",
"climate_entity2_id": "2. základná klíma", "climate_entity2_id": "2. základná klíma",
@@ -290,6 +323,7 @@
"auto_regulation_mode": "Samoregulácia", "auto_regulation_mode": "Samoregulácia",
"auto_regulation_dtemp": "Regulačný prah", "auto_regulation_dtemp": "Regulačný prah",
"auto_regulation_periode_min": "Regulačné minimálne obdobie", "auto_regulation_periode_min": "Regulačné minimálne obdobie",
"auto_regulation_use_device_temp": "Použite vnútornú teplotu podkladu",
"inverse_switch_command": "Inverzný prepínací príkaz", "inverse_switch_command": "Inverzný prepínací príkaz",
"auto_fan_mode": "Režim automatického ventilátora" "auto_fan_mode": "Režim automatického ventilátora"
}, },
@@ -298,6 +332,7 @@
"heater_entity2_id": "Voliteľné ID entity 2. ohrievača. Ak sa nepoužíva, nechajte prázdne", "heater_entity2_id": "Voliteľné ID entity 2. ohrievača. Ak sa nepoužíva, nechajte prázdne",
"heater_entity3_id": "Voliteľné ID entity 3. ohrievača. Ak sa nepoužíva, nechajte prázdne", "heater_entity3_id": "Voliteľné ID entity 3. ohrievača. Ak sa nepoužíva, nechajte prázdne",
"heater_entity4_id": "Voliteľné ID entity 4. ohrievača. Ak sa nepoužíva, nechajte prázdne", "heater_entity4_id": "Voliteľné ID entity 4. ohrievača. Ak sa nepoužíva, nechajte prázdne",
"heater_keep_alive": "Voliteľný interval obnovy stavu spínača ohrievača. Ak to nie je potrebné, nechajte prázdne.",
"proportional_function": "Algoritmus, ktorý sa má použiť (TPI je zatiaľ jediný)", "proportional_function": "Algoritmus, ktorý sa má použiť (TPI je zatiaľ jediný)",
"climate_entity_id": "ID základnej klimatickej entity", "climate_entity_id": "ID základnej klimatickej entity",
"climate_entity2_id": "2. základný identifikátor klimatickej entity", "climate_entity2_id": "2. základný identifikátor klimatickej entity",
@@ -311,6 +346,7 @@
"auto_regulation_mode": "Automatické nastavenie cieľovej teploty", "auto_regulation_mode": "Automatické nastavenie cieľovej teploty",
"auto_regulation_dtemp": "Hranica v °, pod ktorou sa zmena teploty neodošle", "auto_regulation_dtemp": "Hranica v °, pod ktorou sa zmena teploty neodošle",
"auto_regulation_periode_min": "Trvanie v minútach medzi dvoma aktualizáciami predpisov", "auto_regulation_periode_min": "Trvanie v minútach medzi dvoma aktualizáciami predpisov",
"auto_regulation_use_device_temp": "Na urýchlenie samoregulácie použite prípadný vnútorný snímač teploty podkladu",
"inverse_switch_command": "V prípade spínača s pilotným vodičom a diódou možno budete musieť príkaz invertovať", "inverse_switch_command": "V prípade spínača s pilotným vodičom a diódou možno budete musieť príkaz invertovať",
"auto_fan_mode": "Automaticky aktivujte ventilátor, keď je potrebné veľké vykurovanie/chladenie" "auto_fan_mode": "Automaticky aktivujte ventilátor, keď je potrebné veľké vykurovanie/chladenie"
} }
@@ -333,24 +369,7 @@
"title": "Predvoľby - {name}", "title": "Predvoľby - {name}",
"description": "Pre každú predvoľbu zadajte cieľovú teplotu (0, ak chcete predvoľbu ignorovať)", "description": "Pre každú predvoľbu zadajte cieľovú teplotu (0, ak chcete predvoľbu ignorovať)",
"data": { "data": {
"eco_temp": "Teplota v predvoľbe Eco",
"comfort_temp": "Prednastavená teplota v komfortnom režime",
"boost_temp": "Teplota v prednastavení Boost",
"frost_temp": "Teplota v prednastavení Frost protection",
"eco_ac_temp": "Teplota v režime Eco prednastavená pre režim AC",
"comfort_ac_temp": "Teplota v režime Comfort je prednastavená pre režim AC",
"boost_ac_temp": "Prednastavená teplota v režime Boost pre režim AC",
"use_presets_central_config": "Použite konfiguráciu centrálnych predvolieb" "use_presets_central_config": "Použite konfiguráciu centrálnych predvolieb"
},
"data_description": {
"eco_temp": "Teplota v predvoľbe Eco",
"comfort_temp": "Prednastavená teplota v komfortnom režime",
"boost_temp": "Teplota v prednastavení Boost",
"frost_temp": "Teplota v prednastavenej ochrane proti mrazu",
"eco_ac_temp": "Teplota v režime Eco prednastavená pre režim AC",
"comfort_ac_temp": "Teplota v režime Comfort je prednastavená pre režim AC",
"boost_ac_temp": "Prednastavená teplota v režime Boost pre režim AC",
"use_presets_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálnych predvolieb. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu predvolieb pre tento VTherm"
} }
}, },
"window": { "window": {
@@ -362,7 +381,8 @@
"window_auto_open_threshold": "Prah poklesu teploty pre automatickú detekciu otvoreného okna (v °/hodina)", "window_auto_open_threshold": "Prah poklesu teploty pre automatickú detekciu otvoreného okna (v °/hodina)",
"window_auto_close_threshold": "Prahová hodnota zvýšenia teploty pre koniec automatickej detekcie (v °/hodina)", "window_auto_close_threshold": "Prahová hodnota zvýšenia teploty pre koniec automatickej detekcie (v °/hodina)",
"window_auto_max_duration": "Maximálne trvanie automatickej detekcie otvoreného okna (v min)", "window_auto_max_duration": "Maximálne trvanie automatickej detekcie otvoreného okna (v min)",
"use_window_central_config": "Použite centrálnu konfiguráciu okna" "use_window_central_config": "Použite centrálnu konfiguráciu okna",
"window_action": "Akcia"
}, },
"data_description": { "data_description": {
"window_sensor_entity_id": "Nechajte prázdne, ak nemáte použiť žiadny okenný senzor", "window_sensor_entity_id": "Nechajte prázdne, ak nemáte použiť žiadny okenný senzor",
@@ -370,7 +390,8 @@
"window_auto_open_threshold": "Odporúčaná hodnota: medzi 3 a 10. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne", "window_auto_open_threshold": "Odporúčaná hodnota: medzi 3 a 10. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne",
"window_auto_close_threshold": "Odporúčaná hodnota: 0. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne", "window_auto_close_threshold": "Odporúčaná hodnota: 0. Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne",
"window_auto_max_duration": "Odporúčaná hodnota: 60 (jedna hodina). Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne", "window_auto_max_duration": "Odporúčaná hodnota: 60 (jedna hodina). Ak sa nepoužíva automatická detekcia otvoreného okna, nechajte prázdne",
"use_window_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálneho okna. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu okna pre tento VTherm" "use_window_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálneho okna. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu okna pre tento VTherm",
"window_action": "Akcia, ktorá sa má vykonať, ak sa okno zistí ako otvorené"
} }
}, },
"motion": { "motion": {
@@ -410,29 +431,14 @@
} }
}, },
"presence": { "presence": {
"title": "Riadenie prítomnosti", "title": "Prítommnosť - {name}",
"description": "Atribúty správy prítomnosti.\nPoskytuje senzor prítomnosti vášho domova (pravda, ak je niekto prítomný).\nPotom zadajte buď predvoľbu, ktorá sa má použiť, keď je senzor prítomnosti nepravdivý, alebo posun teploty, ktorý sa má použiť.\nAk je zadaná predvoľba, posun sa nepoužije.\nAk sa nepoužije, ponechajte zodpovedajúce entity_id prázdne.", "description": "Atribúty riadenia prítomnosti.\nPoskytuje senzor prítomnosti vášho domova (pravda, je niekto prítomný) a poskytuje zodpovedajúce prednastavené nastavenie teploty.",
"data": { "data": {
"presence_sensor_entity_id": "ID entity senzora prítomnosti (pravda je prítomná)", "presence_sensor_entity_id": "Senzor prítomnosti",
"eco_away_temp": "Teplota v prednastavenej Eco, keď nie je žiadna prítomnosť", "use_presence_central_config": "Použite konfiguráciu centrálnej prítomnosti teploty. Ak chcete použiť špecifické entity teploty, zrušte začiarknutie"
"comfort_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný",
"boost_away_temp": "Prednastavená teplota v režime Boost, keď nie je prítomný",
"frost_away_temp": "Prednastavená teplota v režime Frost protection, keď nie je prítomný",
"eco_ac_away_temp": "Teplota v prednastavenej Eco, keď nie je prítomná v režime AC",
"comfort_ac_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný v režime AC",
"boost_ac_away_temp": "Teplota v prednastavenom Boost, keď nie je prítomný v režime AC",
"use_presence_central_config": "Použite centrálnu konfiguráciu prítomnosti"
}, },
"data_description": { "data_description": {
"presence_sensor_entity_id": "ID entity senzora prítomnosti", "presence_sensor_entity_id": "ID entity senzora prítomnosti"
"eco_away_temp": "Teplota v prednastavenej Eco, keď nie je žiadna prítomnosť",
"comfort_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný",
"boost_away_temp": "Prednastavená teplota v režime Boost, keď nie je prítomný",
"frost_away_temp": "Teplota v Prednastavená ochrana pred mrazom, keď nie je prítomný",
"eco_ac_away_temp": "Teplota v prednastavenej Eco, keď nie je prítomná v režime AC",
"comfort_ac_away_temp": "Teplota v režime Comfort je prednastavená, keď nie je prítomný v režime AC",
"boost_ac_away_temp": "Teplota v prednastavenom Boost, keď nie je prítomný v režime AC",
"use_presence_central_config": "Začiarknite, ak chcete použiť konfiguráciu centrálnej prítomnosti. Zrušte začiarknutie, ak chcete použiť špecifickú konfiguráciu prítomnosti pre tento VTherm"
} }
}, },
"advanced": { "advanced": {
@@ -458,7 +464,8 @@
"unknown": "Neočakávaná chyba", "unknown": "Neočakávaná chyba",
"unknown_entity": "Neznáme ID entity", "unknown_entity": "Neznáme ID entity",
"window_open_detection_method": "Mala by sa použiť iba jedna metóda detekcie otvoreného okna. Použite senzor alebo automatickú detekciu cez teplotný prah, ale nie oboje", "window_open_detection_method": "Mala by sa použiť iba jedna metóda detekcie otvoreného okna. Použite senzor alebo automatickú detekciu cez teplotný prah, ale nie oboje",
"no_central_config": "Nemôžete zaškrtnúť „použiť centrálnu konfiguráciu“, pretože sa nenašla žiadna centrálna konfigurácia. Aby ste ho mohli používať, musíte si vytvoriť všestranný termostat typu „Central Configuration“." "no_central_config": "Nemôžete zaškrtnúť „použiť centrálnu konfiguráciu“, pretože sa nenašla žiadna centrálna konfigurácia. Aby ste ho mohli používať, musíte si vytvoriť všestranný termostat typu „Central Configuration“.",
"service_configuration_format": "Formát konfigurácie služby je nesprávny"
}, },
"abort": { "abort": {
"already_configured": "Zariadenie je už nakonfigurované" "already_configured": "Zariadenie je už nakonfigurované"
@@ -491,6 +498,22 @@
"auto_fan_high": "Vysoký", "auto_fan_high": "Vysoký",
"auto_fan_turbo": "Turbo" "auto_fan_turbo": "Turbo"
} }
},
"window_action": {
"options": {
"window_turn_off": "Vypnúť",
"window_fan_only": "Len ventilátor",
"window_frost_temp": "Ochrana pred mrazom",
"window_eco_temp": "Eco"
}
},
"presets": {
"options": {
"frost": "Ochrana proti mrazu",
"eco": "Eco",
"comfort": "Komfort",
"boost": "Boost"
}
} }
}, },
"entity": { "entity": {
@@ -506,6 +529,53 @@
} }
} }
} }
},
"number": {
"frost_temp": {
"name": "Mráz"
},
"eco_temp": {
"name": "Eco"
},
"comfort_temp": {
"name": "Komfort"
},
"boost_temp": {
"name": "Boost"
},
"frost_ac_temp": {
"name": "Mráz ac"
},
"eco_ac_temp": {
"name": "Eco ac"
},
"comfort_ac_temp": {
"name": "Komfort ac"
},
"boost_ac_temp": {
"name": "Boost ac"
},
"frost_away_temp": {
"name": "Mráz mimo"
},
"eco_away_temp": {
"name": "Eko mimo"
},
"comfort_away_temp": {
"name": "Komfort mimo"
},
"boost_away_temp": {
"name": "Boost mimo"
},
"eco_ac_away_temp": {
"name": "Eco ac mimo"
},
"comfort_ac_away_temp": {
"name": "Komfort ac mimo"
},
"boost_ac_away_temp": {
"name": "Boost ac mimo"
}
} }
} }
} }
@@ -30,6 +30,7 @@ from homeassistant.components.number import SERVICE_SET_VALUE
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import async_call_later from homeassistant.helpers.event import async_call_later
from homeassistant.util.unit_conversion import TemperatureConverter
from .const import UnknownEntity, overrides from .const import UnknownEntity, overrides
from .keep_alive import IntervalCaller from .keep_alive import IntervalCaller
@@ -663,7 +664,7 @@ class UnderlyingClimate(UnderlyingEntity):
def temperature_unit(self) -> str: def temperature_unit(self) -> str:
"""Get the temperature_unit""" """Get the temperature_unit"""
if not self.is_initialized: if not self.is_initialized:
return UnitOfTemperature.CELSIUS return self._hass.config.units.temperature_unit
return self._underlying_climate.temperature_unit return self._underlying_climate.temperature_unit
@property @property
@@ -704,7 +705,7 @@ class UnderlyingClimate(UnderlyingEntity):
if not hasattr(self._underlying_climate, "current_temperature"): if not hasattr(self._underlying_climate, "current_temperature"):
return None return None
return self._underlying_climate.current_temperature return self._hass.states.get(self._entity_id).attributes.get("current_temperature")
def turn_aux_heat_on(self) -> None: def turn_aux_heat_on(self) -> None:
"""Turn auxiliary heater on.""" """Turn auxiliary heater on."""
@@ -731,8 +732,12 @@ class UnderlyingClimate(UnderlyingEntity):
self._underlying_climate.min_temp is not None self._underlying_climate.min_temp is not None
and self._underlying_climate is not None and self._underlying_climate is not None
): ):
min_val = self._underlying_climate.min_temp min_val = TemperatureConverter.convert(
max_val = self._underlying_climate.max_temp self._underlying_climate.min_temp, self._underlying_climate.temperature_unit, self._hass.config.units.temperature_unit
)
max_val = TemperatureConverter.convert(
self._underlying_climate.max_temp, self._underlying_climate.temperature_unit, self._hass.config.units.temperature_unit
)
new_value = max(min_val, min(value, max_val)) new_value = max(min_val, min(value, max_val))
else: else:
+1 -1
View File
@@ -3,5 +3,5 @@
"content_in_root": false, "content_in_root": false,
"render_readme": true, "render_readme": true,
"hide_default_branch": false, "hide_default_branch": false,
"homeassistant": "2024.3.1" "homeassistant": "2024.4.3"
} }
+1 -1
View File
@@ -1 +1 @@
homeassistant==2024.3.1 homeassistant==2024.6.1
+113
View File
@@ -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
+1 -1
View File
@@ -69,7 +69,7 @@ async def test_add_a_central_config_with_boiler(
assert api.nb_active_device_for_boiler == 0 assert api.nb_active_device_for_boiler == 0
assert api.nb_active_device_for_boiler_threshold_entity is not None assert api.nb_active_device_for_boiler_threshold_entity is not None
assert api.nb_active_device_for_boiler_threshold is 1 # the default value is 1 assert api.nb_active_device_for_boiler_threshold == 1 # the default value is 1
async def test_update_central_boiler_state_simple( async def test_update_central_boiler_state_simple(
+1 -1
View File
@@ -514,4 +514,4 @@ async def test_migration_of_central_config(
assert api.nb_active_device_for_boiler == 0 assert api.nb_active_device_for_boiler == 0
assert api.nb_active_device_for_boiler_threshold_entity is not None assert api.nb_active_device_for_boiler_threshold_entity is not None
assert api.nb_active_device_for_boiler_threshold is 1 # the default value is 1 assert api.nb_active_device_for_boiler_threshold == 1 # the default value is 1
+24 -24
View File
@@ -83,7 +83,7 @@ async def test_movement_management_time_not_enough(
await send_ext_temperature_change_event(entity, 10, event_timestamp) await send_ext_temperature_change_event(entity, 10, event_timestamp)
await send_presence_change_event(entity, True, False, event_timestamp) await send_presence_change_event(entity, True, False, event_timestamp)
assert entity.presence_state is "on" assert entity.presence_state == "on"
# starts detecting motion with time not enough # starts detecting motion with time not enough
with patch( with patch(
@@ -110,7 +110,7 @@ async def test_movement_management_time_not_enough(
assert entity.target_temperature == 18 assert entity.target_temperature == 18
# state is not changed if time is not enough # state is not changed if time is not enough
assert entity.motion_state is None assert entity.motion_state is None
assert entity.presence_state is "on" assert entity.presence_state == "on"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
# Change is not confirmed # Change is not confirmed
@@ -141,8 +141,8 @@ async def test_movement_management_time_not_enough(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because motion is detected yet # because motion is detected yet
assert entity.target_temperature == 19 assert entity.target_temperature == 19
assert entity.motion_state is "on" assert entity.motion_state == "on"
assert entity.presence_state is "on" assert entity.presence_state == "on"
# stop detecting motion with off delay too low # stop detecting motion with off delay too low
with patch( with patch(
@@ -167,8 +167,8 @@ async def test_movement_management_time_not_enough(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because no motion is detected yet # because no motion is detected yet
assert entity.target_temperature == 19 assert entity.target_temperature == 19
assert entity.motion_state is "on" assert entity.motion_state == "on"
assert entity.presence_state is "on" assert entity.presence_state == "on"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
# The heater must heat now # The heater must heat now
@@ -199,8 +199,8 @@ async def test_movement_management_time_not_enough(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because no motion is detected yet # because no motion is detected yet
assert entity.target_temperature == 18 assert entity.target_temperature == 18
assert entity.motion_state is "off" assert entity.motion_state == "off"
assert entity.presence_state is "on" assert entity.presence_state == "on"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
# The heater must stop heating now # The heater must stop heating now
@@ -280,7 +280,7 @@ async def test_movement_management_time_enough_and_presence(
await send_ext_temperature_change_event(entity, 10, event_timestamp) await send_ext_temperature_change_event(entity, 10, event_timestamp)
await send_presence_change_event(entity, True, False, event_timestamp) await send_presence_change_event(entity, True, False, event_timestamp)
assert entity.presence_state is "on" assert entity.presence_state == "on"
# starts detecting motion # starts detecting motion
with patch( with patch(
@@ -302,8 +302,8 @@ async def test_movement_management_time_enough_and_presence(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because motion is detected yet -> switch to Boost mode # because motion is detected yet -> switch to Boost mode
assert entity.target_temperature == 19 assert entity.target_temperature == 19
assert entity.motion_state is "on" assert entity.motion_state == "on"
assert entity.presence_state is "on" assert entity.presence_state == "on"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
# Change is confirmed. Heater should be started # Change is confirmed. Heater should be started
@@ -331,8 +331,8 @@ async def test_movement_management_time_enough_and_presence(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because no motion is detected yet # because no motion is detected yet
assert entity.target_temperature == 18 assert entity.target_temperature == 18
assert entity.motion_state is "off" assert entity.motion_state == "off"
assert entity.presence_state is "on" assert entity.presence_state == "on"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
assert mock_heater_on.call_count == 0 assert mock_heater_on.call_count == 0
@@ -412,7 +412,7 @@ async def test_movement_management_time_enoughand_not_presence(
await send_ext_temperature_change_event(entity, 10, event_timestamp) await send_ext_temperature_change_event(entity, 10, event_timestamp)
await send_presence_change_event(entity, False, True, event_timestamp) await send_presence_change_event(entity, False, True, event_timestamp)
assert entity.presence_state is "off" assert entity.presence_state == "off"
# starts detecting motion # starts detecting motion
with patch( with patch(
@@ -434,8 +434,8 @@ async def test_movement_management_time_enoughand_not_presence(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because motion is detected yet -> switch to Boost away mode # because motion is detected yet -> switch to Boost away mode
assert entity.target_temperature == 19.1 assert entity.target_temperature == 19.1
assert entity.motion_state is "on" assert entity.motion_state == "on"
assert entity.presence_state is "off" assert entity.presence_state == "off"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
# Change is confirmed. Heater should be started # Change is confirmed. Heater should be started
@@ -463,8 +463,8 @@ async def test_movement_management_time_enoughand_not_presence(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
# because no motion is detected yet # because no motion is detected yet
assert entity.target_temperature == 18.1 assert entity.target_temperature == 18.1
assert entity.motion_state is "off" assert entity.motion_state == "off"
assert entity.presence_state is "off" assert entity.presence_state == "off"
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
# 18.1 starts heating with a low on_percent # 18.1 starts heating with a low on_percent
@@ -546,7 +546,7 @@ async def test_movement_management_with_stop_during_condition(
await send_ext_temperature_change_event(entity, 10, event_timestamp) await send_ext_temperature_change_event(entity, 10, event_timestamp)
await send_presence_change_event(entity, False, True, event_timestamp) await send_presence_change_event(entity, False, True, event_timestamp)
assert entity.presence_state is "off" assert entity.presence_state == "off"
# starts detecting motion # starts detecting motion
with patch( with patch(
@@ -569,7 +569,7 @@ async def test_movement_management_with_stop_during_condition(
# because motion is detected yet -> switch to Boost mode # because motion is detected yet -> switch to Boost mode
assert entity.target_temperature == 18 assert entity.target_temperature == 18
assert entity.motion_state is None assert entity.motion_state is None
assert entity.presence_state is "off" assert entity.presence_state == "off"
# Send a stop detection # Send a stop detection
event_timestamp = now - timedelta(minutes=4) event_timestamp = now - timedelta(minutes=4)
@@ -580,7 +580,7 @@ async def test_movement_management_with_stop_during_condition(
assert entity.preset_mode is PRESET_ACTIVITY assert entity.preset_mode is PRESET_ACTIVITY
assert entity.target_temperature == 18 assert entity.target_temperature == 18
assert entity.motion_state is None assert entity.motion_state is None
assert entity.presence_state is "off" assert entity.presence_state == "off"
# Resend a start detection # Resend a start detection
event_timestamp = now - timedelta(minutes=3) event_timestamp = now - timedelta(minutes=3)
@@ -592,10 +592,10 @@ async def test_movement_management_with_stop_during_condition(
# still no motion detected # still no motion detected
assert entity.target_temperature == 18 assert entity.target_temperature == 18
assert entity.motion_state is None assert entity.motion_state is None
assert entity.presence_state is "off" assert entity.presence_state == "off"
await try_condition1(None) await try_condition1(None)
# We should have switch this time # We should have switch this time
assert entity.target_temperature == 19 # Boost assert entity.target_temperature == 19 # Boost
assert entity.motion_state is "on" # switch to movement on assert entity.motion_state == "on" # switch to movement on
assert entity.presence_state is "off" # Non change assert entity.presence_state == "off" # Non change