From 638e007c21e91ba2809611da4c59ad97115e2980 Mon Sep 17 00:00:00 2001 From: Jean-Marc Collin Date: Wed, 18 Jan 2023 23:40:55 +0100 Subject: [PATCH] =?UTF-8?q?Add=20min=5Ftemp=20and=20max=5Ftemp=20in=20conf?= =?UTF-8?q?iguration=20#17=20Mise=20en=20s=C3=A9curit=C3=A9=20du=20thermos?= =?UTF-8?q?tat=20si=20pas=20de=20changement=20de=20temp=C3=A9rature=20#18?= =?UTF-8?q?=20Add=20a=20configurable=20minimal=20delay=20of=20activation?= =?UTF-8?q?=20#19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../versatile_thermostat/climate.py | 159 +++++++++--------- .../versatile_thermostat/config_flow.py | 43 ++++- .../versatile_thermostat/const.py | 8 + .../versatile_thermostat/prop_algorithm.py | 26 ++- .../versatile_thermostat/strings.json | 24 ++- .../versatile_thermostat/translations/en.json | 24 ++- .../versatile_thermostat/translations/fr.json | 24 ++- 7 files changed, 213 insertions(+), 95 deletions(-) diff --git a/custom_components/versatile_thermostat/climate.py b/custom_components/versatile_thermostat/climate.py index 839dcf3..25136dc 100644 --- a/custom_components/versatile_thermostat/climate.py +++ b/custom_components/versatile_thermostat/climate.py @@ -96,6 +96,10 @@ from .const import ( SERVICE_SET_PRESENCE, SERVICE_SET_PRESET_TEMPERATURE, PRESET_AWAY_SUFFIX, + CONF_SECURITY_DELAY_MIN, + CONF_MINIMAL_ACTIVATION_DELAY, + CONF_TEMP_MAX, + CONF_TEMP_MIN, ) from .prop_algorithm import PropAlgorithm @@ -133,6 +137,10 @@ async def async_setup_entry( tpi_coef_ext = entry.data.get(CONF_TPI_COEF_EXT) presence_sensor_entity_id = entry.data.get(CONF_PRESENCE_SENSOR) power_temp = entry.data.get(CONF_PRESET_POWER) + temp_min = entry.data.get(CONF_TEMP_MIN) + temp_max = entry.data.get(CONF_TEMP_MAX) + security_delay_min = entry.data.get(CONF_SECURITY_DELAY_MIN) + minimal_activation_delay = entry.data.get(CONF_MINIMAL_ACTIVATION_DELAY) presets = {} for (key, value) in CONF_PRESETS.items(): @@ -161,6 +169,8 @@ async def async_setup_entry( proportional_function, temp_sensor_entity_id, ext_temp_sensor_entity_id, + temp_min, + temp_max, power_sensor_entity_id, max_power_sensor_entity_id, window_sensor_entity_id, @@ -176,6 +186,8 @@ async def async_setup_entry( tpi_coef_ext, presence_sensor_entity_id, power_temp, + security_delay_min, + minimal_activation_delay, ) ], True, @@ -223,6 +235,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): proportional_function, temp_sensor_entity_id, ext_temp_sensor_entity_id, + temp_min, + temp_max, power_sensor_entity_id, max_power_sensor_entity_id, window_sensor_entity_id, @@ -238,6 +252,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): tpi_coef_ext, presence_sensor_entity_id, power_temp, + security_delay_min, + minimal_activation_delay, ) -> None: """Initialize the thermostat.""" @@ -253,6 +269,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self._proportional_function = proportional_function self._temp_sensor_entity_id = temp_sensor_entity_id self._ext_temp_sensor_entity_id = ext_temp_sensor_entity_id + self._attr_max_temp = temp_max + self._attr_min_temp = temp_min self._power_sensor_entity_id = power_sensor_entity_id self._max_power_sensor_entity_id = max_power_sensor_entity_id self._window_sensor_entity_id = window_sensor_entity_id @@ -273,7 +291,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self._presence_sensor_entity_id = presence_sensor_entity_id self._power_temp = power_temp - self._presence_on = self._presence_sensor_entity_id != None + self._presence_on = self._presence_sensor_entity_id is not None # TODO if self.ac_mode: # self.hvac_list = [HVAC_MODE_COOL, HVAC_MODE_OFF] @@ -335,14 +353,21 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): ) self._tpi_coef_ext = 0 + self._security_delay_min = security_delay_min + self._minimal_activation_delay = minimal_activation_delay + self._last_temperature_mesure = datetime.now() + self._last_ext_temperature_mesure = datetime.now() + self._security_state = False + self._saved_hvac_mode = None + # Initiate the ProportionalAlgorithm self._prop_algorithm = PropAlgorithm( self._proportional_function, self._tpi_coef_int, self._tpi_coef_ext, self._cycle_min, + self._minimal_activation_delay, ) - self._async_cancel_cycle = None self._window_call_cancel = None self._motion_call_cancel = None @@ -654,7 +679,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): _LOGGER.debug("%s - Calling async_startup", self) @callback - def _async_startup_internal(*_): + async def _async_startup_internal(*_): _LOGGER.debug("%s - Calling async_startup_internal", self) need_write_state = False temperature_state = self.hass.states.get(self._temp_sensor_entity_id) @@ -667,7 +692,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self, float(temperature_state.state), ) - self._async_update_temp(temperature_state) + await self._async_update_temp(temperature_state) need_write_state = True if self._ext_temp_sensor_entity_id: @@ -683,7 +708,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self, float(ext_temperature_state.state), ) - self._async_update_ext_temp(ext_temperature_state) + await self._async_update_ext_temp(ext_temperature_state) else: _LOGGER.debug( "%s - external temperature sensor have NOT been retrieved cause unknown or unavailable", @@ -790,7 +815,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): await self.get_my_previous_state() if self.hass.state == CoreState.running: - _async_startup_internal() + await _async_startup_internal() else: self.hass.bus.async_listen_once( EVENT_HOMEASSISTANT_START, _async_startup_internal @@ -869,7 +894,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): if new_state is None or new_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN): return - self._async_update_temp(new_state) + await self._async_update_temp(new_state) self.recalculate() await self._async_control_heating(force=False) @@ -884,7 +909,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): if new_state is None or new_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN): return - self._async_update_ext_temp(new_state) + await self._async_update_ext_temp(new_state) self.recalculate() await self._async_control_heating(force=False) @@ -1028,24 +1053,32 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self.async_write_ha_state() @callback - def _async_update_temp(self, state): + async def _async_update_temp(self, state): """Update thermostat with latest state from sensor.""" try: cur_temp = float(state.state) if math.isnan(cur_temp) or math.isinf(cur_temp): raise ValueError(f"Sensor has illegal state {state.state}") self._cur_temp = cur_temp + self._last_temperature_mesure = datetime.now() + # try to restart if we were in security mode + if self._security_state: + await self.async_set_hvac_mode(self._saved_hvac_mode) except ValueError as ex: _LOGGER.error("Unable to update temperature from sensor: %s", ex) @callback - def _async_update_ext_temp(self, state): + async def _async_update_ext_temp(self, state): """Update thermostat with latest state from sensor.""" try: cur_ext_temp = float(state.state) if math.isnan(cur_ext_temp) or math.isinf(cur_ext_temp): raise ValueError(f"Sensor has illegal state {state.state}") self._cur_ext_temp = cur_ext_temp + self._last_ext_temperature_mesure = datetime.now() + # try to restart if we were in security mode + if self._security_state: + await self.async_set_hvac_mode(self._saved_hvac_mode) except ValueError as ex: _LOGGER.error("Unable to update external temperature from sensor: %s", ex) @@ -1235,6 +1268,28 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self._saved_preset_mode if self._saved_preset_mode else PRESET_NONE ) + def check_date_temperature(self) -> bool: + """Check if last temperature date is too long""" + now = datetime.now() + delta_temp = (now - self._last_temperature_mesure).total_seconds() / 60.0 + delta_ext_temp = ( + now - self._last_ext_temperature_mesure + ).total_seconds() / 60.0 + if ( + delta_temp > self._security_delay_min + or delta_ext_temp > self._security_delay_min + ): + _LOGGER.warning( + "%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f)", + self, + self._security_delay_min, + delta_temp, + delta_ext_temp, + ) + return False + + return True + async def _async_control_heating(self, force=False, time=None): """The main function used to run the calculation at each cycle""" @@ -1251,17 +1306,18 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): on_time_sec: int = self._prop_algorithm.on_time_sec off_time_sec: int = self._prop_algorithm.off_time_sec _LOGGER.info( - "%s - Running new cycle at %s. on_time_sec=%.0f, off_time_sec=%.0f", + "%s - Running new cycle at %s. on_time_sec=%.0f, off_time_sec=%.0f, security_state=%s", self, time, on_time_sec, off_time_sec, + self._security_state, ) # Cancel eventual previous cycle if any if self._async_cancel_cycle is not None: if force: - _LOGGER.debug("%s - we force a new cycle") + _LOGGER.debug("%s - we force a new cycle", self) self._async_cancel_cycle() self._async_cancel_cycle = None else: @@ -1271,21 +1327,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): ) self._should_relaunch_control_heating = True return - # await self._async_cancel_cycle() - # self._async_cancel_cycle = None - # Don't turn off if we will turn on just after - # if on_time_sec <= 0: - # await self._async_heater_turn_off() if self._hvac_mode == HVAC_MODE_HEAT and on_time_sec > 0: - # _LOGGER.info( - # "%s - start heating for %d min %d sec ", - # self, - # on_time_sec // 60, - # on_time_sec % 60, - # ) - # - # await self._async_heater_turn_on() async def _turn_on_off_later( on: bool, time, heater_action, next_cycle_action @@ -1294,6 +1337,13 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): self._async_cancel_cycle() self._async_cancel_cycle = None + if time > 0 and on is True and self.check_date_temperature() is False: + _LOGGER.warning("%s - Set the thermostat into security mode") + self._security_state = True + self._saved_hvac_mode = self.hvac_mode + await self.async_set_hvac_mode(HVAC_MODE_OFF) + return + action_label = "start" if on else "stop" if self._should_relaunch_control_heating: _LOGGER.debug( @@ -1331,30 +1381,6 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): next_cycle_action=_turn_off_later, ) - # if self._async_cancel_cycle: - # self._async_cancel_cycle() - # self._async_cancel_cycle = None - # - # if self._should_relaunch_control_heating: - # _LOGGER.debug("Don't stop cause a cycle have to be relaunch") - # self._should_relaunch_control_heating = False - # await self._async_control_heating() - # return - # else: - # _LOGGER.info( - # "%s - stop heating for %d min %d sec", - # self, - # off_time_sec // 60, - # off_time_sec % 60, - # ) - # await self._async_heater_turn_off() - # self.update_custom_attributes() - # self._async_cancel_cycle = async_call_later( - # self.hass, - # off_time_sec, - # _turn_off_later, - # ) - async def _turn_off_later(_): await _turn_on_off_later( on=False, @@ -1363,36 +1389,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): next_cycle_action=_turn_on_later, ) - # if self._async_cancel_cycle: - # self._async_cancel_cycle() - # self._async_cancel_cycle = None - # - # if self._should_relaunch_control_heating: - # _LOGGER.debug("Don't stop cause a cycle have to be relaunch") - # self._should_relaunch_control_heating = False - # await self._async_control_heating() - # return - # else: - # _LOGGER.info( - # "%s - stop heating for %d min %d sec", - # self, - # off_time_sec // 60, - # off_time_sec % 60, - # ) - # await self._async_heater_turn_off() - # self.update_custom_attributes() - # self._async_cancel_cycle = async_call_later( - # self.hass, - # on_time_sec, - # _turn_on_later, - # ) await _turn_on_later(None) - # # Program turn off - # self._async_cancel_cycle = async_call_later( - # self.hass, - # on_time_sec, - # _turn_off_later, - # ) elif self._is_device_active: _LOGGER.info( @@ -1446,10 +1443,16 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): "tpi_coef_ext": self._tpi_coef_ext, "saved_preset_mode": self._saved_preset_mode, "saved_target_temp": self._saved_target_temp, + "saved_hvac_mode": self._saved_hvac_mode, "window_state": self._window_state, "motion_state": self._motion_state, "overpowering_state": self._overpowering_state, "presence_state": self._presence_state, + "security_delay_min": self._security_delay_min, + "last_temperature_datetime": self._last_temperature_mesure.isoformat(), + "last_ext_temperature_datetime": self._last_ext_temperature_mesure.isoformat(), + "security_state": self._security_state, + "minimal_activation_delay_sec": self._minimal_activation_delay, "last_update_datetime": datetime.now().isoformat(), } self.async_write_ha_state() diff --git a/custom_components/versatile_thermostat/config_flow.py b/custom_components/versatile_thermostat/config_flow.py index f51713f..a0be2ac 100644 --- a/custom_components/versatile_thermostat/config_flow.py +++ b/custom_components/versatile_thermostat/config_flow.py @@ -45,6 +45,10 @@ from .const import ( CONF_TPI_COEF_INT, CONF_PRESENCE_SENSOR, PROPORTIONAL_FUNCTION_TPI, + CONF_SECURITY_DELAY_MIN, + CONF_MINIMAL_ACTIVATION_DELAY, + CONF_TEMP_MAX, + CONF_TEMP_MIN, ) # from .climate import VersatileThermostat @@ -117,6 +121,8 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): PROPORTIONAL_FUNCTION_TPI, ] ), + vol.Required(CONF_TEMP_MIN, default=7): vol.Coerce(float), + vol.Required(CONF_TEMP_MAX, default=35): vol.Coerce(float), } ) @@ -174,6 +180,15 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): } ) + self.STEP_ADVANCED_DATA_SCHEMA = vol.Schema( + { + vol.Required( + CONF_MINIMAL_ACTIVATION_DELAY, default=10 + ): cv.positive_int, + vol.Required(CONF_SECURITY_DELAY_MIN, default=60): cv.positive_int, + } + ) + async def validate_input(self, data: dict) -> dict[str]: """Validate the user input allows us to connect. @@ -303,6 +318,17 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): "presence", self.STEP_PRESENCE_DATA_SCHEMA, user_input, + self.async_step_advanced, + ) + + async def async_step_advanced(self, user_input: dict | None = None) -> FlowResult: + """Handle the advanced parameter flow steps""" + _LOGGER.debug("Into ConfigFlow.async_step_advanced user_input=%s", user_input) + + return await self.generic_step( + "advanced", + self.STEP_ADVANCED_DATA_SCHEMA, + user_input, self.async_finalize, # pylint: disable=no-member ) @@ -417,7 +443,7 @@ class VersatileThermostatOptionsFlowHandler( "power", self.STEP_POWER_DATA_SCHEMA, user_input, - self.async_step_presence, # pylint: disable=no-member + self.async_step_presence, ) async def async_step_presence(self, user_input: dict | None = None) -> FlowResult: @@ -430,7 +456,20 @@ class VersatileThermostatOptionsFlowHandler( "presence", self.STEP_PRESENCE_DATA_SCHEMA, user_input, - self.async_finalize, # pylint: disable=no-member + self.async_step_advanced, + ) + + async def async_step_advanced(self, user_input: dict | None = None) -> FlowResult: + """Handle the advanced flow steps""" + _LOGGER.debug( + "Into OptionsFlowHandler.async_step_advanced user_input=%s", user_input + ) + + return await self.generic_step( + "advanced", + self.STEP_ADVANCED_DATA_SCHEMA, + user_input, + self.async_finalize, ) async def async_finalize(self): diff --git a/custom_components/versatile_thermostat/const.py b/custom_components/versatile_thermostat/const.py index c68a4bd..bd40b7b 100644 --- a/custom_components/versatile_thermostat/const.py +++ b/custom_components/versatile_thermostat/const.py @@ -35,6 +35,10 @@ CONF_TPI_COEF_INT = "tpi_coef_int" CONF_TPI_COEF_EXT = "tpi_coef_ext" CONF_PRESENCE_SENSOR = "presence_sensor_entity_id" CONF_PRESET_POWER = "power_temp" +CONF_MINIMAL_ACTIVATION_DELAY = "minimal_activation_delay" +CONF_TEMP_MIN = "temp_min" +CONF_TEMP_MAX = "temp_max" +CONF_SECURITY_DELAY_MIN = "security_delay_min" CONF_PRESETS = { p: f"{p}_temp" @@ -81,6 +85,10 @@ ALL_CONF = ( CONF_TPI_COEF_INT, CONF_TPI_COEF_EXT, CONF_PRESENCE_SENSOR, + CONF_MINIMAL_ACTIVATION_DELAY, + CONF_TEMP_MIN, + CONF_TEMP_MAX, + CONF_SECURITY_DELAY_MIN, ] + CONF_PRESETS_VALUES + CONF_PRESETS_AWAY_VALUES, diff --git a/custom_components/versatile_thermostat/prop_algorithm.py b/custom_components/versatile_thermostat/prop_algorithm.py index aa247e0..bfa24a9 100644 --- a/custom_components/versatile_thermostat/prop_algorithm.py +++ b/custom_components/versatile_thermostat/prop_algorithm.py @@ -1,5 +1,4 @@ import logging -import math _LOGGER = logging.getLogger(__name__) @@ -21,20 +20,22 @@ class PropAlgorithm: tpi_coef_int, tpi_coef_ext, cycle_min: int, + minimal_activation_delay: int, ): """Initialisation of the Proportional Algorithm""" _LOGGER.debug( - "Creation new PropAlgorithm function_type: %s, tpi_coef_int: %s, tpi_coef_ext: %s, cycle_min:%d", + "Creation new PropAlgorithm function_type: %s, tpi_coef_int: %s, tpi_coef_ext: %s, cycle_min:%d, minimal_activation_delay:%d", function_type, tpi_coef_int, tpi_coef_ext, cycle_min, + minimal_activation_delay, ) - # TODO test function_type, bias, cycle_min self._function = function_type self._tpi_coef_int = tpi_coef_int self._tpi_coef_ext = tpi_coef_ext self._cycle_min = cycle_min + self._minimal_activation_delay = minimal_activation_delay self._on_percent = 0 self._on_time_sec = 0 self._off_time_sec = self._cycle_min * 60 @@ -74,12 +75,19 @@ class PropAlgorithm: self._on_time_sec = self._on_percent * self._cycle_min * 60 # Do not heat for less than xx sec - if self._on_time_sec < PROPORTIONAL_MIN_DURATION_SEC: - _LOGGER.debug( - "No heating period due to heating period too small (%f < %f)", - self._on_time_sec, - PROPORTIONAL_MIN_DURATION_SEC, - ) + if self._on_time_sec < self._minimal_activation_delay: + if self._on_time_sec > 0: + _LOGGER.info( + "No heating period due to heating period too small (%f < %f)", + self._on_time_sec, + self._minimal_activation_delay, + ) + else: + _LOGGER.debug( + "No heating period due to heating period too small (%f < %f)", + self._on_time_sec, + self._minimal_activation_delay, + ) self._on_time_sec = 0 self._off_time_sec = self._cycle_min * 60 - self._on_time_sec diff --git a/custom_components/versatile_thermostat/strings.json b/custom_components/versatile_thermostat/strings.json index ebde636..5c0e596 100644 --- a/custom_components/versatile_thermostat/strings.json +++ b/custom_components/versatile_thermostat/strings.json @@ -12,7 +12,9 @@ "temperature_sensor_entity_id": "Temperature sensor entity id", "external_temperature_sensor_entity_id": "External temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", - "proportional_function": "Algorithm to use (TPI is the only one for now)" + "proportional_function": "Algorithm to use (TPI is the only one for now)", + "temp_min": "Minimal temperature allowed", + "temp_max": "Maximal temperature allowed" } }, "tpi": { @@ -69,6 +71,14 @@ "comfort_away_temp": "Temperature in Comfort preset when no presence", "boost_away_temp": "Temperature in Boost preset when no presence" } + }, + "advanced": { + "title": "Advanced parameters", + "description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.", + "data": { + "minimal_activation_delay": "Delay in secondes under which the equipment will not be activated", + "security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state" + } } }, "error": { @@ -91,7 +101,9 @@ "temperature_sensor_entity_id": "Temperature sensor entity id", "external_temperature_sensor_entity_id": "External temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", - "proportional_function": "Algorithm to use (TPI is the only one for now)" + "proportional_function": "Algorithm to use (TPI is the only one for now)", + "temp_min": "Minimal temperature allowed", + "temp_max": "Maximal temperature allowed" } }, "tpi": { @@ -148,6 +160,14 @@ "comfort_away_temp": "Temperature in Comfort preset when no presence", "boost_away_temp": "Temperature in Boost preset when no presence" } + }, + "advanced": { + "title": "Advanced parameters", + "description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.", + "data": { + "minimal_activation_delay": "Delay in secondes under which the equipment will not be activated", + "security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state" + } } }, "error": { diff --git a/custom_components/versatile_thermostat/translations/en.json b/custom_components/versatile_thermostat/translations/en.json index ebde636..5c0e596 100644 --- a/custom_components/versatile_thermostat/translations/en.json +++ b/custom_components/versatile_thermostat/translations/en.json @@ -12,7 +12,9 @@ "temperature_sensor_entity_id": "Temperature sensor entity id", "external_temperature_sensor_entity_id": "External temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", - "proportional_function": "Algorithm to use (TPI is the only one for now)" + "proportional_function": "Algorithm to use (TPI is the only one for now)", + "temp_min": "Minimal temperature allowed", + "temp_max": "Maximal temperature allowed" } }, "tpi": { @@ -69,6 +71,14 @@ "comfort_away_temp": "Temperature in Comfort preset when no presence", "boost_away_temp": "Temperature in Boost preset when no presence" } + }, + "advanced": { + "title": "Advanced parameters", + "description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.", + "data": { + "minimal_activation_delay": "Delay in secondes under which the equipment will not be activated", + "security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state" + } } }, "error": { @@ -91,7 +101,9 @@ "temperature_sensor_entity_id": "Temperature sensor entity id", "external_temperature_sensor_entity_id": "External temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", - "proportional_function": "Algorithm to use (TPI is the only one for now)" + "proportional_function": "Algorithm to use (TPI is the only one for now)", + "temp_min": "Minimal temperature allowed", + "temp_max": "Maximal temperature allowed" } }, "tpi": { @@ -148,6 +160,14 @@ "comfort_away_temp": "Temperature in Comfort preset when no presence", "boost_away_temp": "Temperature in Boost preset when no presence" } + }, + "advanced": { + "title": "Advanced parameters", + "description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.", + "data": { + "minimal_activation_delay": "Delay in secondes under which the equipment will not be activated", + "security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state" + } } }, "error": { diff --git a/custom_components/versatile_thermostat/translations/fr.json b/custom_components/versatile_thermostat/translations/fr.json index daa0741..da6af51 100644 --- a/custom_components/versatile_thermostat/translations/fr.json +++ b/custom_components/versatile_thermostat/translations/fr.json @@ -12,7 +12,9 @@ "temperature_sensor_entity_id": "Température sensor entity id", "external_temperature_sensor_entity_id": "Temperature exterieure sensor entity id", "cycle_min": "Durée du cycle (minutes)", - "proportional_function": "Algorithm à utiliser (Seul TPI est disponible pour l'instant)" + "proportional_function": "Algorithm à utiliser (Seul TPI est disponible pour l'instant)", + "temp_min": "Température minimale permise", + "temp_max": "Température maximale permise" } }, "tpi": { @@ -69,6 +71,14 @@ "comfort_away_temp": "Température en preset Comfort en cas d'absence", "boost_away_temp": "Température en preset Boost en cas d'absence" } + }, + "advanced": { + "title": "Parameters avancés", + "description": "Configuration des paramètres avancés. Laissez les valeurs par défaut si vous ne savez pas ce que vous faites.\nCes paramètres peuvent induire des mauvais comportements du thermostat.", + "data": { + "minimal_activation_delay": "Délai en seondes en-dessous duquel l'équipement ne sera pas activé", + "security_delay_min": "Délai maximal autorisé en minutes entre 2 mesures de températures. Au-dessus de ce délai, le thermostat se mettra en position éteinte de sécurité" + } } }, "error": { @@ -91,7 +101,9 @@ "temperature_sensor_entity_id": "Température sensor entity id", "external_temperature_sensor_entity_id": "Temperature exterieure sensor entity id", "cycle_min": "Durée du cycle (minutes)", - "proportional_function": "Algorithm à utiliser (Seul TPI est disponible pour l'instant)" + "proportional_function": "Algorithm à utiliser (Seul TPI est disponible pour l'instant)", + "temp_min": "Température minimale permise", + "temp_max": "Température maximale permise" } }, "tpi": { @@ -148,6 +160,14 @@ "comfort_away_temp": "Température en preset Comfort en cas d'absence", "boost_away_temp": "Température en preset Boost en cas d'absence" } + }, + "advanced": { + "title": "Parameters avancés", + "description": "Configuration des paramètres avancés. Laissez les valeurs par défaut si vous ne savez pas ce que vous faites.\nCes paramètres peuvent induire des mauvais comportements du thermostat.", + "data": { + "minimal_activation_delay": "Délai en seondes en-dessous duquel l'équipement ne sera pas activé", + "security_delay_min": "Délai maximal autorisé en minutes entre 2 mesures de températures. Au-dessus de ce délai, le thermostat se mettra en position éteinte de sécurité" + } } }, "error": {