From 47f5aa9595f56a274fbeeb920f30f7ba2d5d8b26 Mon Sep 17 00:00:00 2001 From: Jean-Marc Collin Date: Fri, 15 Dec 2023 18:37:25 +0000 Subject: [PATCH] Add central config into ConfigFlow --- .../versatile_thermostat/config_flow.py | 825 +++++++++++++----- .../versatile_thermostat/const.py | 17 + .../versatile_thermostat/strings.json | 171 +++- .../versatile_thermostat/translations/en.json | 171 +++- .../versatile_thermostat/translations/fr.json | 166 +++- .../versatile_thermostat/vtherm_api.py | 45 +- 6 files changed, 1025 insertions(+), 370 deletions(-) diff --git a/custom_components/versatile_thermostat/config_flow.py b/custom_components/versatile_thermostat/config_flow.py index e29474b..69be174 100644 --- a/custom_components/versatile_thermostat/config_flow.py +++ b/custom_components/versatile_thermostat/config_flow.py @@ -84,6 +84,7 @@ from .const import ( CONF_TEMP_MIN, CONF_THERMOSTAT_TYPE, CONF_THERMOSTAT_SWITCH, + CONF_THERMOSTAT_CENTRAL_CONFIG, CONF_CLIMATE, CONF_CLIMATE_2, CONF_CLIMATE_3, @@ -107,11 +108,25 @@ from .const import ( CONF_INVERSE_SWITCH, UnknownEntity, WindowOpenDetectionMethod, + NoCentralConfig, CONF_AUTO_FAN_MODES, CONF_AUTO_FAN_MODE, CONF_AUTO_FAN_HIGH, + CENTRAL_CONFIG_NAME, + CONF_USE_MAIN_CENTRAL_CONFIG, + CONF_USE_TPI_CENTRAL_CONFIG, + CONF_USE_WINDOW_CENTRAL_CONFIG, + CONF_USE_MOTION_CENTRAL_CONFIG, + CONF_USE_POWER_CENTRAL_CONFIG, + CONF_USE_PRESENCE_CENTRAL_CONFIG, + CONF_USE_PRESETS_CENTRAL_CONFIG, + CONF_USE_ADVANCED_CENTRAL_CONFIG, ) +from .vtherm_api import VersatileThermostatAPI + +COMES_FROM = "comes_from" + _LOGGER = logging.getLogger(__name__) @@ -161,13 +176,26 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): VERSION = 1 _infos: dict + _placeholders = { + CONF_NAME: "", + } def __init__(self, infos) -> None: super().__init__() _LOGGER.debug("CTOR BaseConfigFlow infos: %s", infos) self._infos = infos + + # VTherm API should have been initialized before arriving here + vtherm_api = VersatileThermostatAPI.get_vtherm_api() + self._central_config = vtherm_api.find_central_configuration() + + self._init_feature_flags(infos) + self._init_central_config_flags(infos) + self._init_schemas() + + def _init_feature_flags(self, infos): + """Fix features selection depending to infos""" is_empty: bool = not bool(infos) - # Fix features selection depending to infos self._infos[CONF_USE_WINDOW_FEATURE] = ( is_empty or self._infos.get(CONF_WINDOW_SENSOR) is not None @@ -184,34 +212,105 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None ) + def _init_central_config_flags(self, infos): + """Initialisation of central configuration flags""" + is_empty: bool = not bool(infos) + for config in ( + CONF_USE_MAIN_CENTRAL_CONFIG, + CONF_USE_TPI_CENTRAL_CONFIG, + CONF_USE_WINDOW_CENTRAL_CONFIG, + CONF_USE_MOTION_CENTRAL_CONFIG, + CONF_USE_POWER_CENTRAL_CONFIG, + CONF_USE_PRESENCE_CENTRAL_CONFIG, + CONF_USE_ADVANCED_CENTRAL_CONFIG, + ): + self._infos[config] = self._central_config is not None and ( + is_empty or self._infos.get(config) is None + ) + + def _init_schemas(self): + """Init the schemas""" + + # TODO those constants are instanciated each time a VTherm is created. + # This is not necessary and should be real constants or static members self.STEP_USER_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name { - vol.Required(CONF_NAME): cv.string, vol.Required( CONF_THERMOSTAT_TYPE, default=CONF_THERMOSTAT_SWITCH ): selector.SelectSelector( selector.SelectSelectorConfig( options=CONF_THERMOSTAT_TYPES, translation_key="thermostat_type" ) - ), - vol.Required(CONF_TEMP_SENSOR): selector.EntitySelector( - selector.EntitySelectorConfig( - domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] - ), - ), + ) + } + ) + + self.STEP_CENTRAL_MAIN_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name + { vol.Required(CONF_EXTERNAL_TEMP_SENSOR): selector.EntitySelector( selector.EntitySelectorConfig( domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] ), ), - vol.Required(CONF_CYCLE_MIN, default=5): cv.positive_int, vol.Required(CONF_TEMP_MIN, default=7): vol.Coerce(float), vol.Required(CONF_TEMP_MAX, default=35): vol.Coerce(float), + } + ) + + self.STEP_CENTRAL_TPI_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name + { + vol.Required(CONF_TPI_COEF_INT, default=0.6): vol.Coerce(float), + vol.Required(CONF_TPI_COEF_EXT, default=0.01): vol.Coerce(float), + } + ) + + self.STEP_CENTRAL_WINDOW_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(CONF_WINDOW_DELAY, default=30): cv.positive_int, + vol.Optional( + CONF_WINDOW_AUTO_OPEN_THRESHOLD, default=3 + ): vol.Coerce(float), + vol.Optional( + CONF_WINDOW_AUTO_CLOSE_THRESHOLD, default=0 + ): vol.Coerce(float), + vol.Optional( + CONF_WINDOW_AUTO_MAX_DURATION, default=30 + ): cv.positive_int, + } + ) + ) + + self.STEP_CENTRAL_MOTION_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(CONF_MOTION_DELAY, default=30): cv.positive_int, + vol.Optional(CONF_MOTION_OFF_DELAY, default=300): cv.positive_int, + vol.Optional(CONF_MOTION_PRESET, default="comfort"): vol.In( + CONF_PRESETS_SELECTIONABLE + ), + vol.Optional(CONF_NO_MOTION_PRESET, default="eco"): vol.In( + CONF_PRESETS_SELECTIONABLE + ), + } + ) + ) + + self.STEP_MAIN_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name + { + vol.Required(CONF_NAME): cv.string, + vol.Required(CONF_TEMP_SENSOR): selector.EntitySelector( + selector.EntitySelectorConfig( + domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] + ), + ), + vol.Required(CONF_CYCLE_MIN, default=5): cv.positive_int, vol.Optional(CONF_DEVICE_POWER, default="1"): vol.Coerce(float), vol.Optional(CONF_USE_WINDOW_FEATURE, default=False): cv.boolean, vol.Optional(CONF_USE_MOTION_FEATURE, default=False): cv.boolean, vol.Optional(CONF_USE_POWER_FEATURE, default=False): cv.boolean, vol.Optional(CONF_USE_PRESENCE_FEATURE, default=False): cv.boolean, + vol.Required(CONF_USE_MAIN_CENTRAL_CONFIG, default=True): cv.boolean, } ) @@ -324,20 +423,27 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): self.STEP_TPI_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name { - vol.Required(CONF_TPI_COEF_INT, default=0.6): vol.Coerce(float), - vol.Required(CONF_TPI_COEF_EXT, default=0.01): vol.Coerce(float), + vol.Required(CONF_USE_TPI_CENTRAL_CONFIG, default=True): cv.boolean, } ) self.STEP_PRESETS_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name { - vol.Optional(v, default=0): vol.Coerce(float) - for (k, v) in CONF_PRESETS.items() + vol.Required(CONF_USE_PRESETS_CENTRAL_CONFIG, default=True): cv.boolean, } ) - self.STEP_PRESETS_WITH_AC_DATA_SCHEMA = ( # pylint: disable=invalid-name + self.STEP_CENTRAL_PRESETS_DATA_SCHEMA = ( vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(v, default=0): vol.Coerce(float) + for (k, v) in CONF_PRESETS.items() + } + ) + ) + + self.STEP_CENTRAL_PRESETS_WITH_AC_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name # pylint: disable=invalid-name { vol.Optional(v, default=0): vol.Coerce(float) for (k, v) in CONF_PRESETS_WITH_AC.items() @@ -352,13 +458,27 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): domain=[BINARY_SENSOR_DOMAIN, INPUT_BOOLEAN_DOMAIN] ), ), - vol.Optional(CONF_WINDOW_DELAY, default=30): cv.positive_int, - vol.Optional(CONF_WINDOW_AUTO_OPEN_THRESHOLD): vol.Coerce(float), - vol.Optional(CONF_WINDOW_AUTO_CLOSE_THRESHOLD): vol.Coerce(float), - vol.Optional(CONF_WINDOW_AUTO_MAX_DURATION): cv.positive_int, + vol.Required(CONF_USE_WINDOW_CENTRAL_CONFIG, default=True): cv.boolean, } ) + self.STEP_CENTRAL_WINDOW_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(CONF_WINDOW_DELAY, default=30): cv.positive_int, + vol.Optional( + CONF_WINDOW_AUTO_OPEN_THRESHOLD, default=3 + ): vol.Coerce(float), + vol.Optional( + CONF_WINDOW_AUTO_CLOSE_THRESHOLD, default=0 + ): vol.Coerce(float), + vol.Optional( + CONF_WINDOW_AUTO_MAX_DURATION, default=30 + ): cv.positive_int, + } + ) + ) + self.STEP_MOTION_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name { vol.Optional(CONF_MOTION_SENSOR): selector.EntitySelector( @@ -366,30 +486,62 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): domain=[BINARY_SENSOR_DOMAIN, INPUT_BOOLEAN_DOMAIN] ), ), - vol.Optional(CONF_MOTION_DELAY, default=30): cv.positive_int, - vol.Optional(CONF_MOTION_OFF_DELAY, default=300): cv.positive_int, - vol.Optional(CONF_MOTION_PRESET, default="comfort"): vol.In( - CONF_PRESETS_SELECTIONABLE - ), - vol.Optional(CONF_NO_MOTION_PRESET, default="eco"): vol.In( - CONF_PRESETS_SELECTIONABLE - ), + vol.Required(CONF_USE_MOTION_CENTRAL_CONFIG, default=True): cv.boolean, } ) + self.STEP_CENTRAL_MOTION_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(CONF_MOTION_DELAY, default=30): cv.positive_int, + vol.Optional(CONF_MOTION_OFF_DELAY, default=300): cv.positive_int, + vol.Optional(CONF_MOTION_PRESET, default="comfort"): vol.In( + CONF_PRESETS_SELECTIONABLE + ), + vol.Optional(CONF_NO_MOTION_PRESET, default="eco"): vol.In( + CONF_PRESETS_SELECTIONABLE + ), + } + ) + ) + + self.STEP_CENTRAL_POWER_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(CONF_POWER_SENSOR): selector.EntitySelector( + selector.EntitySelectorConfig( + domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] + ), + ), + vol.Optional(CONF_MAX_POWER_SENSOR): selector.EntitySelector( + selector.EntitySelectorConfig( + domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] + ), + ), + vol.Optional(CONF_PRESET_POWER, default="13"): vol.Coerce(float), + } + ) + ) + self.STEP_POWER_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name { - vol.Optional(CONF_POWER_SENSOR): selector.EntitySelector( - selector.EntitySelectorConfig( - domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] - ), - ), - vol.Optional(CONF_MAX_POWER_SENSOR): selector.EntitySelector( - selector.EntitySelectorConfig( - domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN] - ), - ), - vol.Optional(CONF_PRESET_POWER, default="13"): vol.Coerce(float), + vol.Required(CONF_USE_POWER_CENTRAL_CONFIG, default=True): cv.boolean, + } + ) + + self.STEP_CENTRAL_PRESENCE_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name + { + vol.Optional(v, default=17): vol.Coerce(float) + for (k, v) in CONF_PRESETS_AWAY.items() + } + ) + ) + + self.STEP_CENTRAL_PRESENCE_WITH_AC_DATA_SCHEMA = ( + { # pylint: disable=invalid-name + vol.Optional(v, default=17): vol.Coerce(float) + for (k, v) in CONF_PRESETS_AWAY_WITH_AC.items() } ) @@ -404,31 +556,27 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): ] ), ), - } - ).extend( - { - vol.Optional(v, default=17): vol.Coerce(float) - for (k, v) in CONF_PRESETS_AWAY.items() + vol.Required( + CONF_USE_PRESENCE_CENTRAL_CONFIG, default=True + ): cv.boolean, } ) - self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA = ( # pylint: disable=invalid-name - vol.Schema( + self.STEP_CENTRAL_ADVANCED_DATA_SCHEMA = ( + vol.Schema( # pylint: disable=invalid-name { - vol.Optional(CONF_PRESENCE_SENSOR): selector.EntitySelector( - selector.EntitySelectorConfig( - domain=[ - PERSON_DOMAIN, - BINARY_SENSOR_DOMAIN, - INPUT_BOOLEAN_DOMAIN, - ] - ), - ), - } - ).extend( - { - vol.Optional(v, default=17): vol.Coerce(float) - for (k, v) in CONF_PRESETS_AWAY_WITH_AC.items() + vol.Required( + CONF_MINIMAL_ACTIVATION_DELAY, default=10 + ): cv.positive_int, + vol.Required(CONF_SECURITY_DELAY_MIN, default=60): cv.positive_int, + vol.Required( + CONF_SECURITY_MIN_ON_PERCENT, + default=DEFAULT_SECURITY_MIN_ON_PERCENT, + ): vol.Coerce(float), + vol.Required( + CONF_SECURITY_DEFAULT_ON_PERCENT, + default=DEFAULT_SECURITY_DEFAULT_ON_PERCENT, + ): vol.Coerce(float), } ) ) @@ -436,17 +584,8 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): self.STEP_ADVANCED_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name { vol.Required( - CONF_MINIMAL_ACTIVATION_DELAY, default=10 - ): cv.positive_int, - vol.Required(CONF_SECURITY_DELAY_MIN, default=60): cv.positive_int, - vol.Required( - CONF_SECURITY_MIN_ON_PERCENT, - default=DEFAULT_SECURITY_MIN_ON_PERCENT, - ): vol.Coerce(float), - vol.Required( - CONF_SECURITY_DEFAULT_ON_PERCENT, - default=DEFAULT_SECURITY_DEFAULT_ON_PERCENT, - ): vol.Coerce(float), + CONF_USE_ADVANCED_CENTRAL_CONFIG, default=True + ): cv.boolean, } ) @@ -489,6 +628,24 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): ) raise WindowOpenDetectionMethod(CONF_WINDOW_SENSOR) + # Check that is USE_CENTRAL config is used, that a central config exists + if self._central_config is None: + for conf in [ + CONF_USE_MAIN_CENTRAL_CONFIG, + CONF_USE_TPI_CENTRAL_CONFIG, + CONF_USE_WINDOW_CENTRAL_CONFIG, + CONF_USE_MOTION_CENTRAL_CONFIG, + CONF_USE_POWER_CENTRAL_CONFIG, + CONF_USE_PRESENCE_CENTRAL_CONFIG, + CONF_USE_PRESETS_CENTRAL_CONFIG, + CONF_USE_ADVANCED_CENTRAL_CONFIG, + ]: + if data.get(conf) is True: + _LOGGER.error( + "The use of central configuration need a central configuration Versatile Thermostat instance" + ) + raise NoCentralConfig(conf) + def merge_user_input(self, data_schema: vol.Schema, user_input: dict): """For each schema entry not in user_input, set or remove values in infos""" self._infos.update(user_input) @@ -521,6 +678,8 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): errors[str(err)] = "unknown_entity" except WindowOpenDetectionMethod as err: errors[str(err)] = "window_open_detection_method" + except NoCentralConfig as err: + errors[str(err)] = "no_central_config" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" @@ -534,18 +693,56 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): data_schema=data_schema, suggested_values=defaults ) # pylint: disable=invalid-name - return self.async_show_form(step_id=step_id, data_schema=ds, errors=errors) + return self.async_show_form( + step_id=step_id, + data_schema=ds, + errors=errors, + description_placeholders=self._placeholders, + ) async def async_step_user(self, user_input: dict | None = None) -> FlowResult: """Handle the flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_user user_input=%s", user_input) return await self.generic_step( - "user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_type + "user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_main ) - async def async_step_type(self, user_input: dict | None = None) -> FlowResult: + async def async_step_main(self, user_input: dict | None = None) -> FlowResult: """Handle the flow steps""" + _LOGGER.debug("Into ConfigFlow.async_step_main user_input=%s", user_input) + + schema = self.STEP_MAIN_DATA_SCHEMA + next_step = self.async_step_type + + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + self._infos[CONF_NAME] = CENTRAL_CONFIG_NAME + schema = self.STEP_CENTRAL_MAIN_DATA_SCHEMA + next_step = self.async_step_tpi + elif user_input and user_input.get(CONF_USE_MAIN_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_main + schema = self.STEP_MAIN_DATA_SCHEMA + # If we come from async_step_spec_main + elif self._infos.get(COMES_FROM) == "async_step_spec_main": + next_step = self.async_step_type + schema = self.STEP_CENTRAL_MAIN_DATA_SCHEMA + + return await self.generic_step("main", schema, user_input, next_step) + + async def async_step_spec_main(self, user_input: dict | None = None) -> FlowResult: + """Handle the specific main flow steps""" + _LOGGER.debug("Into ConfigFlow.async_step_spec_main user_input=%s", user_input) + + schema = self.STEP_CENTRAL_MAIN_DATA_SCHEMA + next_step = self.async_step_type + + self._infos[COMES_FROM] = "async_step_spec_main" + + # This will return to async_step_main (to keep the "main" step) + return await self.generic_step("main", schema, user_input, next_step) + + async def async_step_type(self, user_input: dict | None = None) -> FlowResult: + """Handle the Type flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_type user_input=%s", user_input) if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_SWITCH: @@ -565,18 +762,42 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): ) async def async_step_tpi(self, user_input: dict | None = None) -> FlowResult: - """Handle the flow steps""" + """Handle the TPI flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_tpi user_input=%s", user_input) - return await self.generic_step( - "tpi", self.STEP_TPI_DATA_SCHEMA, user_input, self.async_step_presets + schema = self.STEP_TPI_DATA_SCHEMA + next_step = ( + self.async_step_spec_tpi + if user_input and user_input.get(CONF_USE_TPI_CENTRAL_CONFIG) is False + else self.async_step_presets ) + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_TPI_DATA_SCHEMA + next_step = self.async_step_presets + + return await self.generic_step("tpi", schema, user_input, next_step) + + async def async_step_spec_tpi(self, user_input: dict | None = None) -> FlowResult: + """Handle the specific TPI flow steps""" + _LOGGER.debug("Into ConfigFlow.async_step_spec_tpi user_input=%s", user_input) + + schema = self.STEP_CENTRAL_TPI_DATA_SCHEMA + next_step = self.async_step_presets + + return await self.generic_step("tpi", schema, user_input, next_step) + async def async_step_presets(self, user_input: dict | None = None) -> FlowResult: """Handle the presets flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_presets user_input=%s", user_input) + if self._infos.get(CONF_AC_MODE) is True: + schema_ac_or_not = self.STEP_CENTRAL_PRESETS_WITH_AC_DATA_SCHEMA + else: + schema_ac_or_not = self.STEP_CENTRAL_PRESETS_DATA_SCHEMA + next_step = self.async_step_advanced + schema = self.STEP_PRESETS_DATA_SCHEMA if self._infos[CONF_USE_WINDOW_FEATURE]: next_step = self.async_step_window elif self._infos[CONF_USE_MOTION_FEATURE]: @@ -586,18 +807,46 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): elif self._infos[CONF_USE_PRESENCE_FEATURE]: next_step = self.async_step_presence - if self._infos.get(CONF_AC_MODE) is True: - schema = self.STEP_PRESETS_WITH_AC_DATA_SCHEMA - else: - schema = self.STEP_PRESETS_DATA_SCHEMA + # In Central config -> display the presets_with_ac and goto windows + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_PRESETS_WITH_AC_DATA_SCHEMA + next_step = self.async_step_window + # If comes from async_step_spec_presets + elif self._infos.get(COMES_FROM) == "async_step_spec_presets": + schema = schema_ac_or_not + elif user_input and user_input.get(CONF_USE_PRESETS_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_presets + schema = schema_ac_or_not return await self.generic_step("presets", schema, user_input, next_step) + async def async_step_spec_presets( + self, user_input: dict | None = None + ) -> FlowResult: + """Handle the specific presets flow steps""" + _LOGGER.debug( + "Into ConfigFlow.async_step_spec_presets user_input=%s", user_input + ) + + if self._infos.get(CONF_AC_MODE) is True: + schema = self.STEP_CENTRAL_PRESETS_WITH_AC_DATA_SCHEMA + else: + schema = self.STEP_CENTRAL_PRESETS_DATA_SCHEMA + + self._infos[COMES_FROM] = "async_step_spec_presets" + + next_step = self.async_step_window + + # This will return to async_step_main (to keep the "main" step) + return await self.generic_step("presets", schema, user_input, next_step) + async def async_step_window(self, user_input: dict | None = None) -> FlowResult: """Handle the window sensor flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_window user_input=%s", user_input) + schema = self.STEP_WINDOW_DATA_SCHEMA next_step = self.async_step_advanced + if self._infos[CONF_USE_MOTION_FEATURE]: next_step = self.async_step_motion elif self._infos[CONF_USE_POWER_FEATURE]: @@ -605,66 +854,182 @@ class VersatileThermostatBaseConfigFlow(FlowHandler): elif self._infos[CONF_USE_PRESENCE_FEATURE]: next_step = self.async_step_presence - return await self.generic_step( - "window", self.STEP_WINDOW_DATA_SCHEMA, user_input, next_step + # In Central config -> display the presets_with_ac and goto windows + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_WINDOW_DATA_SCHEMA + next_step = self.async_step_motion + # If comes from async_step_spec_window + elif self._infos.get(COMES_FROM) == "async_step_spec_window": + schema = self.STEP_CENTRAL_WINDOW_DATA_SCHEMA + elif user_input and user_input.get(CONF_USE_WINDOW_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_window + + return await self.generic_step("window", schema, user_input, next_step) + + async def async_step_spec_window( + self, user_input: dict | None = None + ) -> FlowResult: + """Handle the specific window flow steps""" + _LOGGER.debug( + "Into ConfigFlow.async_step_spec_window user_input=%s", user_input ) + schema = self.STEP_CENTRAL_WINDOW_DATA_SCHEMA + + self._infos[COMES_FROM] = "async_step_spec_window" + + next_step = self.async_step_motion + + # This will return to async_step_main (to keep the "main" step) + return await self.generic_step("window", schema, user_input, next_step) + async def async_step_motion(self, user_input: dict | None = None) -> FlowResult: """Handle the window and motion sensor flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_motion user_input=%s", user_input) + schema = self.STEP_MOTION_DATA_SCHEMA next_step = self.async_step_advanced + if self._infos[CONF_USE_POWER_FEATURE]: next_step = self.async_step_power elif self._infos[CONF_USE_PRESENCE_FEATURE]: next_step = self.async_step_presence - return await self.generic_step( - "motion", self.STEP_MOTION_DATA_SCHEMA, user_input, next_step + # In Central config -> display the presets_with_ac and goto windows + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_MOTION_DATA_SCHEMA + next_step = self.async_step_power + # If comes from async_step_spec_motion + elif self._infos.get(COMES_FROM) == "async_step_spec_motion": + schema = self.STEP_CENTRAL_MOTION_DATA_SCHEMA + elif user_input and user_input.get(CONF_USE_MOTION_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_motion + + return await self.generic_step("motion", schema, user_input, next_step) + + async def async_step_spec_motion( + self, user_input: dict | None = None + ) -> FlowResult: + """Handle the specific motion flow steps""" + _LOGGER.debug( + "Into ConfigFlow.async_step_spec_motion user_input=%s", user_input ) + schema = self.STEP_CENTRAL_MOTION_DATA_SCHEMA + + self._infos[COMES_FROM] = "async_step_spec_motion" + + next_step = self.async_step_power + + # This will return to async_step_main (to keep the "main" step) + return await self.generic_step("motion", schema, user_input, next_step) + async def async_step_power(self, user_input: dict | None = None) -> FlowResult: """Handle the power management flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_power user_input=%s", user_input) + schema = self.STEP_POWER_DATA_SCHEMA next_step = self.async_step_advanced + if self._infos[CONF_USE_PRESENCE_FEATURE]: next_step = self.async_step_presence - return await self.generic_step( - "power", - self.STEP_POWER_DATA_SCHEMA, - user_input, - next_step, - ) + # In Central config -> display the presets_with_ac and goto windows + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_POWER_DATA_SCHEMA + next_step = self.async_step_presence + # If comes from async_step_spec_motion + elif self._infos.get(COMES_FROM) == "async_step_spec_power": + schema = self.STEP_CENTRAL_POWER_DATA_SCHEMA + elif user_input and user_input.get(CONF_USE_POWER_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_power + + return await self.generic_step("power", schema, user_input, next_step) + + async def async_step_spec_power(self, user_input: dict | None = None) -> FlowResult: + """Handle the specific power flow steps""" + _LOGGER.debug("Into ConfigFlow.async_step_spec_power user_input=%s", user_input) + + schema = self.STEP_CENTRAL_POWER_DATA_SCHEMA + + self._infos[COMES_FROM] = "async_step_spec_power" + + next_step = self.async_step_presence + + # This will return to async_step_power (to keep the "power" step) + return await self.generic_step("power", schema, user_input, next_step) async def async_step_presence(self, user_input: dict | None = None) -> FlowResult: """Handle the presence management flow steps""" _LOGGER.debug("Into ConfigFlow.async_step_presence user_input=%s", user_input) - if self._infos.get(CONF_AC_MODE) is True: - schema = self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA - else: - schema = self.STEP_PRESENCE_DATA_SCHEMA + schema = self.STEP_PRESENCE_DATA_SCHEMA + next_step = self.async_step_advanced - return await self.generic_step( - "presence", - schema, - user_input, - self.async_step_advanced, + # In Central config -> display the presets_with_ac and goto windows + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_PRESENCE_DATA_SCHEMA + next_step = self.async_step_advanced + # If comes from async_step_spec_presence + elif self._infos.get(COMES_FROM) == "async_step_spec_presence": + schema = self.STEP_CENTRAL_PRESENCE_DATA_SCHEMA + elif user_input and user_input.get(CONF_USE_PRESENCE_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_presence + + return await self.generic_step("presence", schema, user_input, next_step) + + async def async_step_spec_presence( + self, user_input: dict | None = None + ) -> FlowResult: + """Handle the specific preseence flow steps""" + _LOGGER.debug( + "Into ConfigFlow.async_step_spec_presence user_input=%s", user_input ) + schema = self.STEP_CENTRAL_PRESENCE_DATA_SCHEMA + + self._infos[COMES_FROM] = "async_step_spec_presence" + + next_step = self.async_step_advanced + + # This will return to async_step_presence (to keep the "presence" step) + return await self.generic_step("presence", schema, user_input, next_step) + 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 + schema = self.STEP_ADVANCED_DATA_SCHEMA + next_step = self.async_finalize + + # In Central config -> display the presets_with_ac and goto windows + if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG: + schema = self.STEP_CENTRAL_ADVANCED_DATA_SCHEMA + # If comes from async_step_spec_presence + elif self._infos.get(COMES_FROM) == "async_step_spec_advanced": + schema = self.STEP_CENTRAL_ADVANCED_DATA_SCHEMA + elif user_input and user_input.get(CONF_USE_ADVANCED_CENTRAL_CONFIG) is False: + next_step = self.async_step_spec_advanced + + return await self.generic_step("advanced", schema, user_input, next_step) + + async def async_step_spec_advanced( + self, user_input: dict | None = None + ) -> FlowResult: + """Handle the specific advanced flow steps""" + _LOGGER.debug( + "Into ConfigFlow.async_step_spec_advanced user_input=%s", user_input ) + schema = self.STEP_CENTRAL_ADVANCED_DATA_SCHEMA + + self._infos[COMES_FROM] = "async_step_spec_presence" + + next_step = self.async_step_advanced + + # This will return to async_step_presence (to keep the "presence" step) + return await self.generic_step("advanced", schema, user_input, next_step) + async def async_finalize(self): """Should be implemented by Leaf classes""" raise HomeAssistantError( @@ -725,155 +1090,159 @@ class VersatileThermostatOptionsFlowHandler( user_input, ) - return await self.async_step_user() + self._placeholders = { + CONF_NAME: self._infos[CONF_NAME], + } - async def async_step_user(self, user_input: dict | None = None) -> FlowResult: - """Handle the flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_user user_input=%s", user_input - ) + return await self.async_step_main() - return await self.generic_step( - "user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_type - ) + # async def async_step_main(self, user_input: dict | None = None) -> FlowResult: + # """Handle the flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_user user_input=%s", user_input + # ) - async def async_step_type(self, user_input: dict | None = None) -> FlowResult: - """Handle the flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_user user_input=%s", user_input - ) + # return await self.generic_step( + # "user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_type + # ) - if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_SWITCH: - return await self.generic_step( - "type", self.STEP_THERMOSTAT_SWITCH, user_input, self.async_step_tpi - ) - elif self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_VALVE: - return await self.generic_step( - "type", self.STEP_THERMOSTAT_VALVE, user_input, self.async_step_tpi - ) - else: - return await self.generic_step( - "type", - self.STEP_THERMOSTAT_CLIMATE, - user_input, - self.async_step_presets, - ) + # async def async_step_type(self, user_input: dict | None = None) -> FlowResult: + # """Handle the flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_user user_input=%s", user_input + # ) - async def async_step_tpi(self, user_input: dict | None = None) -> FlowResult: - """Handle the tpi flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_tpi user_input=%s", user_input - ) + # if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_SWITCH: + # return await self.generic_step( + # "type", self.STEP_THERMOSTAT_SWITCH, user_input, self.async_step_tpi + # ) + # elif self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_VALVE: + # return await self.generic_step( + # "type", self.STEP_THERMOSTAT_VALVE, user_input, self.async_step_tpi + # ) + # else: + # return await self.generic_step( + # "type", + # self.STEP_THERMOSTAT_CLIMATE, + # user_input, + # self.async_step_presets, + # ) - return await self.generic_step( - "tpi", self.STEP_TPI_DATA_SCHEMA, user_input, self.async_step_presets - ) + # async def async_step_tpi(self, user_input: dict | None = None) -> FlowResult: + # """Handle the tpi flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_tpi user_input=%s", user_input + # ) - async def async_step_presets(self, user_input: dict | None = None) -> FlowResult: - """Handle the presets flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_presets user_input=%s", user_input - ) + # return await self.generic_step( + # "tpi", self.STEP_TPI_DATA_SCHEMA, user_input, self.async_step_presets + # ) - next_step = self.async_step_advanced - if self._infos[CONF_USE_WINDOW_FEATURE]: - next_step = self.async_step_window - elif self._infos[CONF_USE_MOTION_FEATURE]: - next_step = self.async_step_motion - elif self._infos[CONF_USE_POWER_FEATURE]: - next_step = self.async_step_power - elif self._infos[CONF_USE_PRESENCE_FEATURE]: - next_step = self.async_step_presence + # async def async_step_presets(self, user_input: dict | None = None) -> FlowResult: + # """Handle the presets flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_presets user_input=%s", user_input + # ) - if self._infos.get(CONF_AC_MODE) is True: - schema = self.STEP_PRESETS_WITH_AC_DATA_SCHEMA - else: - schema = self.STEP_PRESETS_DATA_SCHEMA + # next_step = self.async_step_advanced + # if self._infos[CONF_USE_WINDOW_FEATURE]: + # next_step = self.async_step_window + # elif self._infos[CONF_USE_MOTION_FEATURE]: + # next_step = self.async_step_motion + # elif self._infos[CONF_USE_POWER_FEATURE]: + # next_step = self.async_step_power + # elif self._infos[CONF_USE_PRESENCE_FEATURE]: + # next_step = self.async_step_presence - return await self.generic_step("presets", schema, user_input, next_step) + # if self._infos.get(CONF_AC_MODE) is True: + # schema = self.STEP_PRESETS_WITH_AC_DATA_SCHEMA + # else: + # schema = self.STEP_PRESETS_DATA_SCHEMA - async def async_step_window(self, user_input: dict | None = None) -> FlowResult: - """Handle the window sensor flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_window user_input=%s", user_input - ) + # return await self.generic_step("presets", schema, user_input, next_step) - next_step = self.async_step_advanced - if self._infos[CONF_USE_MOTION_FEATURE]: - next_step = self.async_step_motion - elif self._infos[CONF_USE_POWER_FEATURE]: - next_step = self.async_step_power - elif self._infos[CONF_USE_PRESENCE_FEATURE]: - next_step = self.async_step_presence - return await self.generic_step( - "window", self.STEP_WINDOW_DATA_SCHEMA, user_input, next_step - ) + # async def async_step_window(self, user_input: dict | None = None) -> FlowResult: + # """Handle the window sensor flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_window user_input=%s", user_input + # ) - async def async_step_motion(self, user_input: dict | None = None) -> FlowResult: - """Handle the window and motion sensor flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_motion user_input=%s", user_input - ) + # next_step = self.async_step_advanced + # if self._infos[CONF_USE_MOTION_FEATURE]: + # next_step = self.async_step_motion + # elif self._infos[CONF_USE_POWER_FEATURE]: + # next_step = self.async_step_power + # elif self._infos[CONF_USE_PRESENCE_FEATURE]: + # next_step = self.async_step_presence + # return await self.generic_step( + # "window", self.STEP_WINDOW_DATA_SCHEMA, user_input, next_step + # ) - next_step = self.async_step_advanced - if self._infos[CONF_USE_POWER_FEATURE]: - next_step = self.async_step_power - elif self._infos[CONF_USE_PRESENCE_FEATURE]: - next_step = self.async_step_presence + # async def async_step_motion(self, user_input: dict | None = None) -> FlowResult: + # """Handle the window and motion sensor flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_motion user_input=%s", user_input + # ) - return await self.generic_step( - "motion", self.STEP_MOTION_DATA_SCHEMA, user_input, next_step - ) + # next_step = self.async_step_advanced + # if self._infos[CONF_USE_POWER_FEATURE]: + # next_step = self.async_step_power + # elif self._infos[CONF_USE_PRESENCE_FEATURE]: + # next_step = self.async_step_presence - async def async_step_power(self, user_input: dict | None = None) -> FlowResult: - """Handle the power management flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_power user_input=%s", user_input - ) + # return await self.generic_step( + # "motion", self.STEP_MOTION_DATA_SCHEMA, user_input, next_step + # ) - next_step = self.async_step_advanced - if self._infos[CONF_USE_PRESENCE_FEATURE]: - next_step = self.async_step_presence + # async def async_step_power(self, user_input: dict | None = None) -> FlowResult: + # """Handle the power management flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_power user_input=%s", user_input + # ) - return await self.generic_step( - "power", - self.STEP_POWER_DATA_SCHEMA, - user_input, - next_step, - ) + # next_step = self.async_step_advanced + # if self._infos[CONF_USE_PRESENCE_FEATURE]: + # next_step = self.async_step_presence - async def async_step_presence(self, user_input: dict | None = None) -> FlowResult: - """Handle the presence management flow steps""" - _LOGGER.debug( - "Into OptionsFlowHandler.async_step_presence user_input=%s", user_input - ) + # return await self.generic_step( + # "power", + # self.STEP_POWER_DATA_SCHEMA, + # user_input, + # next_step, + # ) - if self._infos.get(CONF_AC_MODE) is True: - schema = self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA - else: - schema = self.STEP_PRESENCE_DATA_SCHEMA + # async def async_step_presence(self, user_input: dict | None = None) -> FlowResult: + # """Handle the presence management flow steps""" + # _LOGGER.debug( + # "Into OptionsFlowHandler.async_step_presence user_input=%s", user_input + # ) - return await self.generic_step( - "presence", - schema, - user_input, - self.async_step_advanced, - ) + # if self._infos.get(CONF_AC_MODE) is True: + # schema = self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA + # else: + # schema = self.STEP_PRESENCE_DATA_SCHEMA - 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( + # "presence", + # schema, + # user_input, + # self.async_step_advanced, + # ) - return await self.generic_step( - "advanced", - self.STEP_ADVANCED_DATA_SCHEMA, - user_input, - self.async_end, - ) + # 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 + # ) - async def async_end(self): + # return await self.generic_step( + # "advanced", + # self.STEP_ADVANCED_DATA_SCHEMA, + # user_input, + # self.async_end, + # ) + + async def async_finalize(self): """Finalization of the ConfigEntry creation""" if not self._infos[CONF_USE_WINDOW_FEATURE]: self._infos[CONF_WINDOW_SENSOR] = None diff --git a/custom_components/versatile_thermostat/const.py b/custom_components/versatile_thermostat/const.py index 4b353a9..4b83ba9 100644 --- a/custom_components/versatile_thermostat/const.py +++ b/custom_components/versatile_thermostat/const.py @@ -66,6 +66,7 @@ CONF_SECURITY_DELAY_MIN = "security_delay_min" CONF_SECURITY_MIN_ON_PERCENT = "security_min_on_percent" CONF_SECURITY_DEFAULT_ON_PERCENT = "security_default_on_percent" CONF_THERMOSTAT_TYPE = "thermostat_type" +CONF_THERMOSTAT_CENTRAL_CONFIG = "thermostat_central_config" CONF_THERMOSTAT_SWITCH = "thermostat_over_switch" CONF_THERMOSTAT_CLIMATE = "thermostat_over_climate" CONF_THERMOSTAT_VALVE = "thermostat_over_valve" @@ -103,6 +104,15 @@ CONF_AUTO_FAN_MEDIUM = "auto_fan_medium" CONF_AUTO_FAN_HIGH = "auto_fan_high" CONF_AUTO_FAN_TURBO = "auto_fan_turbo" +CONF_USE_MAIN_CENTRAL_CONFIG = "use_main_central_config" +CONF_USE_TPI_CENTRAL_CONFIG = "use_tpi_central_config" +CONF_USE_WINDOW_CENTRAL_CONFIG = "use_window_central_config" +CONF_USE_MOTION_CENTRAL_CONFIG = "use_motion_central_config" +CONF_USE_POWER_CENTRAL_CONFIG = "use_power_central_config" +CONF_USE_PRESENCE_CENTRAL_CONFIG = "use_presence_central_config" +CONF_USE_PRESETS_CENTRAL_CONFIG = "use_presets_central_config" +CONF_USE_ADVANCED_CENTRAL_CONFIG = "use_advanced_central_config" + DEFAULT_SHORT_EMA_PARAMS = { "max_alpha": 0.5, # In sec @@ -245,6 +255,7 @@ CONF_AUTO_REGULATION_MODES = [ ] CONF_THERMOSTAT_TYPES = [ + CONF_THERMOSTAT_CENTRAL_CONFIG, CONF_THERMOSTAT_SWITCH, CONF_THERMOSTAT_CLIMATE, CONF_THERMOSTAT_VALVE, @@ -276,6 +287,8 @@ ATTR_MEAN_POWER_CYCLE = "mean_cycle_power" AUTO_FAN_DTEMP_THRESHOLD = 2 AUTO_FAN_DEACTIVATED_MODES = ["mute", "auto", "low"] +CENTRAL_CONFIG_NAME = "Central configuration" + # A special regulation parameter suggested by @Maia here: https://github.com/jmcollin78/versatile_thermostat/discussions/154 class RegulationParamSlow: @@ -363,6 +376,10 @@ class WindowOpenDetectionMethod(HomeAssistantError): """Error to indicate there is an error in the window open detection method given.""" +class NoCentralConfig(HomeAssistantError): + """Error to indicate that we try to use a central configuration but no VTherm of type CENTRAL CONFIGURATION has been found""" + + class overrides: # pylint: disable=invalid-name """An annotation to inform overrides""" diff --git a/custom_components/versatile_thermostat/strings.json b/custom_components/versatile_thermostat/strings.json index ac00ca5..5770f71 100644 --- a/custom_components/versatile_thermostat/strings.json +++ b/custom_components/versatile_thermostat/strings.json @@ -4,13 +4,22 @@ "flow_title": "Versatile Thermostat configuration", "step": { "user": { + "title": "Type of Versatile Thermostat", + "data": { + "thermostat_type": "Thermostat type" + }, + "data_description": { + "thermostat_type": "Only one central configuration type is possible" + } + }, + "main": { "title": "Add new Versatile Thermostat", "description": "Main mandatory attributes", "data": { "name": "Name", "thermostat_type": "Thermostat type", "temperature_sensor_entity_id": "Temperature sensor entity id", - "external_temperature_sensor_entity_id": "External temperature sensor entity id", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", @@ -18,7 +27,12 @@ "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", - "use_presence_feature": "Use presence detection" + "use_presence_feature": "Use presence detection", + "use_main_central_config": "Use central main configuration" + }, + "data_description": { + "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific main configuration for this VTherm", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } }, "type": { @@ -71,8 +85,14 @@ "title": "TPI", "description": "Time Proportional Integral attributes", "data": { + "tpi_coef_int": "coef_int", + "tpi_coef_ext": "coef_ext", + "use_tpi_central_config": "Use central TPI configuration" + }, + "data_description": { "tpi_coef_int": "Coefficient to use for internal temperature delta", - "tpi_coef_ext": "Coefficient to use for external temperature delta" + "tpi_coef_ext": "Coefficient to use for external temperature delta", + "use_tpi_central_config": "Check to use the central TPI configuration. Uncheck to use a specific TPI configuration for this VTherm" } }, "presets": { @@ -85,7 +105,8 @@ "frost_temp": "Frost protection preset", "eco_ac_temp": "Eco preset for AC mode", "comfort_ac_temp": "Comfort preset for AC mode", - "boost_ac_temp": "Boost preset for AC mode" + "boost_ac_temp": "Boost preset for AC mode", + "use_presets_central_config": "Use central presets configuration" }, "data_description": { "eco_temp": "Temperature in Eco preset", @@ -94,7 +115,8 @@ "frost_temp": "Temperature in Frost protection preset", "eco_ac_temp": "Temperature in Eco preset for AC mode", "comfort_ac_temp": "Temperature in Comfort preset for AC mode", - "boost_ac_temp": "Temperature in Boost preset for AC mode" + "boost_ac_temp": "Temperature in Boost preset for AC mode", + "use_presets_central_config": "Check to use the central presets configuration. Uncheck to use a specific presets configuration for this VTherm" } }, "window": { @@ -105,14 +127,16 @@ "window_delay": "Window sensor delay (seconds)", "window_auto_open_threshold": "Temperature decrease threshold for automatic window open detection (in °/hours)", "window_auto_close_threshold": "Temperature increase threshold for end of automatic detection (in °/hours)", - "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)" + "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)", + "use_window_central_config": "Use central window configuration" }, "data_description": { "window_sensor_entity_id": "Leave empty if no window sensor should be used", "window_delay": "The delay in seconds before sensor detection is taken into account", "window_auto_open_threshold": "Recommended value: between 3 and 10. Leave empty if automatic window open detection is not used", "window_auto_close_threshold": "Recommended value: 0. Leave empty if automatic window open detection is not used", - "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used" + "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used", + "use_window_central_config": "Check to use the central window configuration. Uncheck to use a specific window configuration for this VTherm" } }, "motion": { @@ -123,23 +147,32 @@ "motion_delay": "Activation delay", "motion_off_delay": "Deactivation delay", "motion_preset": "Motion preset", - "no_motion_preset": "No motion preset" + "no_motion_preset": "No motion preset", + "use_motion_central_config": "Use central motion configuration" }, "data_description": { "motion_sensor_entity_id": "The entity id of the motion sensor", "motion_delay": "Motion activation delay (seconds)", "motion_off_delay": "Motion deactivation delay (seconds)", "motion_preset": "Preset to use when motion is detected", - "no_motion_preset": "Preset to use when no motion is detected" + "no_motion_preset": "Preset to use when no motion is detected", + "use_motion_central_config": "Check to use the central motion configuration. Uncheck to use a specific motion configuration for this VTherm" } }, "power": { "title": "Power management", "description": "Power management attributes.\nGives the power and max power sensor of your home.\nThen specify the power consumption of the heater when on.\nAll sensors and device power should have the same unit (kW or W).\nLeave corresponding entity_id empty if not used.", "data": { + "power_sensor_entity_id": "Power", + "max_power_sensor_entity_id": "Max power", + "power_temp": "Shedding temperature", + "use_power_central_config": "Use central power configuration" + }, + "data_description": { "power_sensor_entity_id": "Power sensor entity id", "max_power_sensor_entity_id": "Max power sensor entity id", - "power_temp": "Temperature for Power shedding" + "power_temp": "Temperature for Power shedding", + "use_power_central_config": "Check to use the central power configuration. Uncheck to use a specific power configuration for this VTherm" } }, "presence": { @@ -153,7 +186,8 @@ "frost_away_temp": "Frost protection preset", "eco_ac_away_temp": "Eco preset in AC mode", "comfort_ac_away_temp": "Comfort preset in AC mode", - "boost_ac_away_temp": "Boost pres et in AC mode" + "boost_ac_away_temp": "Boost pres et in AC mode", + "use_presence_central_config": "Use central presence configuration" }, "data_description": { "presence_sensor_entity_id": "Presence sensor entity id", @@ -163,7 +197,8 @@ "frost_away_temp": "Temperature in Frost protection preset when no presence", "eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode", "comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode", - "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode" + "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode", + "use_presence_central_config": "Check to use the central presence configuration. Uncheck to use a specific presence configuration for this VTherm" } }, "advanced": { @@ -173,20 +208,23 @@ "minimal_activation_delay": "Minimal activation delay", "security_delay_min": "Security delay (in minutes)", "security_min_on_percent": "Minimal power percent to enable security mode", - "security_default_on_percent": "Power percent to use in security mode" + "security_default_on_percent": "Power percent to use in security mode", + "use_advanced_central_config": "Use central advanced configuration" }, "data_description": { "minimal_activation_delay": "Delay in seconds under which the equipment will not be activated", "security_delay_min": "Maximum allowed delay in minutes between two temperature measurements. Above this delay the thermostat will turn to a security off state", "security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of power percent the thermostat won't go into security preset", - "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset" + "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset", + "use_advanced_central_config": "Check to use the central advanced configuration. Uncheck to use a specific advanced configuration for this VTherm" } } }, "error": { "unknown": "Unexpected error", "unknown_entity": "Unknown entity id", - "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both" + "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both", + "no_central_config": "You cannot check 'use central configuration' because no central configuration was found. You need to create a Versatile Thermostat of type 'Central Configuration' to use it." }, "abort": { "already_configured": "Device is already configured" @@ -196,25 +234,39 @@ "flow_title": "Versatile Thermostat configuration", "step": { "user": { - "title": "Add new Versatile Thermostat", + "title": "Type - {name}", + "data": { + "thermostat_type": "Thermostat type" + }, + "data_description": { + "thermostat_type": "Only one central configuration type is possible" + } + }, + "main": { + "title": "{name}", "description": "Main mandatory attributes", "data": { "name": "Name", "thermostat_type": "Thermostat type", - "temperature_sensor_entity_id": "Temperature sensor entity id", - "external_temperature_sensor_entity_id": "External temperature sensor entity id", + "temperature_sensor_entity_id": "Room temperature sensor entity id", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", - "device_power": "Device power (kW)", + "device_power": "Device power", "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", - "use_presence_feature": "Use presence detection" + "use_presence_feature": "Use presence detection", + "use_main_central_config": "Use central main configuration" + }, + "data_description": { + "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific configuration for this VTherm", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } }, "type": { - "title": "Linked entities", + "title": "{name}", "description": "Linked entities attributes", "data": { "heater_entity_id": "1st heater switch", @@ -260,11 +312,17 @@ } }, "tpi": { - "title": "TPI", + "title": "{name}", "description": "Time Proportional Integral attributes", "data": { + "tpi_coef_int": "coef_int", + "tpi_coef_ext": "coef_ext", + "use_tpi_central_config": "Use central TPI configuration" + }, + "data_description": { "tpi_coef_int": "Coefficient to use for internal temperature delta", - "tpi_coef_ext": "Coefficient to use for external temperature delta" + "tpi_coef_ext": "Coefficient to use for external temperature delta", + "use_tpi_central_config": "Check to use the central TPI configuration. Uncheck to use a specific TPI configuration for this VTherm" } }, "presets": { @@ -277,7 +335,8 @@ "frost_temp": "Frost protection preset", "eco_ac_temp": "Eco preset for AC mode", "comfort_ac_temp": "Comfort preset for AC mode", - "boost_ac_temp": "Boost preset for AC mode" + "boost_ac_temp": "Boost preset for AC mode", + "use_presets_central_config": "Use central presets configuration" }, "data_description": { "eco_temp": "Temperature in Eco preset", @@ -286,88 +345,115 @@ "frost_temp": "Temperature in Frost protection preset", "eco_ac_temp": "Temperature in Eco preset for AC mode", "comfort_ac_temp": "Temperature in Comfort preset for AC mode", - "boost_ac_temp": "Temperature in Boost preset for AC mode" + "boost_ac_temp": "Temperature in Boost preset for AC mode", + "use_presets_central_config": "Check to use the central presets configuration. Uncheck to use a specific presets configuration for this VTherm" } }, "window": { - "title": "Window management", - "description": "Open window management.\nLeave corresponding entity_id empty if not used\nYou can also configure automatic window open detection based on temperature decrease", + "title": "{name}", + "description": "Open window management.\nYou can also configure automatic window open detection based on temperature decrease", "data": { "window_sensor_entity_id": "Window sensor entity id", "window_delay": "Window sensor delay (seconds)", "window_auto_open_threshold": "Temperature decrease threshold for automatic window open detection (in °/hours)", "window_auto_close_threshold": "Temperature increase threshold for end of automatic detection (in °/hours)", - "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)" + "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)", + "use_window_central_config": "Use central window configuration" }, "data_description": { "window_sensor_entity_id": "Leave empty if no window sensor should be used", "window_delay": "The delay in seconds before sensor detection is taken into account", "window_auto_open_threshold": "Recommended value: between 3 and 10. Leave empty if automatic window open detection is not used", "window_auto_close_threshold": "Recommended value: 0. Leave empty if automatic window open detection is not used", - "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used" + "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used", + "use_window_central_config": "Check to use the central window configuration. Uncheck to use a specific window configuration for this VTherm" } }, "motion": { - "title": "Motion management", - "description": "Motion sensor management. Preset can switch automatically depending of a motion detection\nLeave corresponding entity_id empty if not used.\nmotion_preset and no_motion_preset should be set to the corresponding preset name", + "title": "{name}", + "description": "Motion management. Preset can switch automatically depending of a motion detection\nLeave corresponding entity_id empty if not used.\nmotion_preset and no_motion_preset should be set to the corresponding preset name", "data": { "motion_sensor_entity_id": "Motion sensor entity id", "motion_delay": "Activation delay", "motion_off_delay": "Deactivation delay", "motion_preset": "Motion preset", - "no_motion_preset": "No motion preset" + "no_motion_preset": "No motion preset", + "use_motion_central_config": "Use central motion configuration" }, "data_description": { "motion_sensor_entity_id": "The entity id of the motion sensor", "motion_delay": "Motion activation delay (seconds)", "motion_off_delay": "Motion deactivation delay (seconds)", "motion_preset": "Preset to use when motion is detected", - "no_motion_preset": "Preset to use when no motion is detected" + "no_motion_preset": "Preset to use when no motion is detected", + "use_motion_central_config": "Check to use the central motion configuration. Uncheck to use a specific motion configuration for this VTherm" } }, "power": { - "title": "Power management", + "title": "{name}", "description": "Power management attributes.\nGives the power and max power sensor of your home.\nThen specify the power consumption of the heater when on.\nAll sensors and device power should have the same unit (kW or W).\nLeave corresponding entity_id empty if not used.", "data": { + "power_sensor_entity_id": "Power", + "max_power_sensor_entity_id": "Max power", + "power_temp": "Shedding temperature", + "use_power_central_config": "Use central power configuration" + }, + "data_description": { "power_sensor_entity_id": "Power sensor entity id", "max_power_sensor_entity_id": "Max power sensor entity id", - "power_temp": "Temperature for Power shedding" + "power_temp": "Temperature for Power shedding", + "use_power_central_config": "Check to use the central power configuration. Uncheck to use a specific power configuration for this VTherm" } }, "presence": { - "title": "Presence management", + "title": "{name}", "description": "Presence management attributes.\nGives the a presence sensor of your home (true is someone is present).\nThen specify either the preset to use when presence sensor is false or the offset in temperature to apply.\nIf preset is given, the offset will not be used.\nLeave corresponding entity_id empty if not used.", "data": { + "presence_sensor_entity_id": "Presence sensor", + "eco_away_temp": "Eco away preset", + "comfort_away_temp": "Comfort away preset", + "boost_away_temp": "Boost away preset", + "eco_ac_away_temp": "Eco away preset in AC mode", + "comfort_ac_away_temp": "Comfort away preset in AC mode", + "boost_ac_away_temp": "Boost away preset in AC mode", + "use_presence_central_config": "Use central presence configuration" + }, + "data_description": { "presence_sensor_entity_id": "Presence sensor entity id", "eco_away_temp": "Temperature in Eco preset when no presence", "comfort_away_temp": "Temperature in Comfort preset when no presence", "boost_away_temp": "Temperature in Boost preset when no presence", + "frost_away_temp": "Temperature in Frost protection preset when no presence", "eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode", "comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode", - "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode" + "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode", + "use_presence_central_config": "Check to use the central presence configuration. Uncheck to use a specific presence configuration for this VTherm" } }, "advanced": { - "title": "Advanced parameters", - "description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThese parameters can lead to very poor temperature control or bad power regulation.", + "title": "{name}", + "description": "Advanced parameters. Leave the default values if you don't know what you are doing.\nThese parameters can lead to very poor temperature control or bad power regulation.", "data": { "minimal_activation_delay": "Minimal activation delay", "security_delay_min": "Security delay (in minutes)", "security_min_on_percent": "Minimal power percent to enable security mode", - "security_default_on_percent": "Power percent to use in security mode" + "security_default_on_percent": "Power percent to use in security mode", + "use_advanced_central_config": "Use central advanced configuration" }, "data_description": { "minimal_activation_delay": "Delay in seconds under which the equipment will not be activated", "security_delay_min": "Maximum allowed delay in minutes between two temperature measurements. Above this delay the thermostat will turn to a security off state", "security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of power percent the thermostat won't go into security preset", - "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset" + "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset", + "use_advanced_central_config": "Check to use the central advanced configuration. Uncheck to use a specific advanced configuration for this VTherm" } } }, "error": { "unknown": "Unexpected error", "unknown_entity": "Unknown entity id", - "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both" + "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both", + "no_central_config": "You cannot check 'use central configuration' because no central configuration was found. You need to create a Versatile Thermostat of type 'Central Configuration' to use it." }, "abort": { "already_configured": "Device is already configured" @@ -376,6 +462,7 @@ "selector": { "thermostat_type": { "options": { + "thermostat_central_config": "Central configuration", "thermostat_over_switch": "Thermostat over a switch", "thermostat_over_climate": "Thermostat over a climate", "thermostat_over_valve": "Thermostat over a valve" diff --git a/custom_components/versatile_thermostat/translations/en.json b/custom_components/versatile_thermostat/translations/en.json index ac00ca5..5770f71 100644 --- a/custom_components/versatile_thermostat/translations/en.json +++ b/custom_components/versatile_thermostat/translations/en.json @@ -4,13 +4,22 @@ "flow_title": "Versatile Thermostat configuration", "step": { "user": { + "title": "Type of Versatile Thermostat", + "data": { + "thermostat_type": "Thermostat type" + }, + "data_description": { + "thermostat_type": "Only one central configuration type is possible" + } + }, + "main": { "title": "Add new Versatile Thermostat", "description": "Main mandatory attributes", "data": { "name": "Name", "thermostat_type": "Thermostat type", "temperature_sensor_entity_id": "Temperature sensor entity id", - "external_temperature_sensor_entity_id": "External temperature sensor entity id", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", @@ -18,7 +27,12 @@ "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", - "use_presence_feature": "Use presence detection" + "use_presence_feature": "Use presence detection", + "use_main_central_config": "Use central main configuration" + }, + "data_description": { + "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific main configuration for this VTherm", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } }, "type": { @@ -71,8 +85,14 @@ "title": "TPI", "description": "Time Proportional Integral attributes", "data": { + "tpi_coef_int": "coef_int", + "tpi_coef_ext": "coef_ext", + "use_tpi_central_config": "Use central TPI configuration" + }, + "data_description": { "tpi_coef_int": "Coefficient to use for internal temperature delta", - "tpi_coef_ext": "Coefficient to use for external temperature delta" + "tpi_coef_ext": "Coefficient to use for external temperature delta", + "use_tpi_central_config": "Check to use the central TPI configuration. Uncheck to use a specific TPI configuration for this VTherm" } }, "presets": { @@ -85,7 +105,8 @@ "frost_temp": "Frost protection preset", "eco_ac_temp": "Eco preset for AC mode", "comfort_ac_temp": "Comfort preset for AC mode", - "boost_ac_temp": "Boost preset for AC mode" + "boost_ac_temp": "Boost preset for AC mode", + "use_presets_central_config": "Use central presets configuration" }, "data_description": { "eco_temp": "Temperature in Eco preset", @@ -94,7 +115,8 @@ "frost_temp": "Temperature in Frost protection preset", "eco_ac_temp": "Temperature in Eco preset for AC mode", "comfort_ac_temp": "Temperature in Comfort preset for AC mode", - "boost_ac_temp": "Temperature in Boost preset for AC mode" + "boost_ac_temp": "Temperature in Boost preset for AC mode", + "use_presets_central_config": "Check to use the central presets configuration. Uncheck to use a specific presets configuration for this VTherm" } }, "window": { @@ -105,14 +127,16 @@ "window_delay": "Window sensor delay (seconds)", "window_auto_open_threshold": "Temperature decrease threshold for automatic window open detection (in °/hours)", "window_auto_close_threshold": "Temperature increase threshold for end of automatic detection (in °/hours)", - "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)" + "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)", + "use_window_central_config": "Use central window configuration" }, "data_description": { "window_sensor_entity_id": "Leave empty if no window sensor should be used", "window_delay": "The delay in seconds before sensor detection is taken into account", "window_auto_open_threshold": "Recommended value: between 3 and 10. Leave empty if automatic window open detection is not used", "window_auto_close_threshold": "Recommended value: 0. Leave empty if automatic window open detection is not used", - "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used" + "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used", + "use_window_central_config": "Check to use the central window configuration. Uncheck to use a specific window configuration for this VTherm" } }, "motion": { @@ -123,23 +147,32 @@ "motion_delay": "Activation delay", "motion_off_delay": "Deactivation delay", "motion_preset": "Motion preset", - "no_motion_preset": "No motion preset" + "no_motion_preset": "No motion preset", + "use_motion_central_config": "Use central motion configuration" }, "data_description": { "motion_sensor_entity_id": "The entity id of the motion sensor", "motion_delay": "Motion activation delay (seconds)", "motion_off_delay": "Motion deactivation delay (seconds)", "motion_preset": "Preset to use when motion is detected", - "no_motion_preset": "Preset to use when no motion is detected" + "no_motion_preset": "Preset to use when no motion is detected", + "use_motion_central_config": "Check to use the central motion configuration. Uncheck to use a specific motion configuration for this VTherm" } }, "power": { "title": "Power management", "description": "Power management attributes.\nGives the power and max power sensor of your home.\nThen specify the power consumption of the heater when on.\nAll sensors and device power should have the same unit (kW or W).\nLeave corresponding entity_id empty if not used.", "data": { + "power_sensor_entity_id": "Power", + "max_power_sensor_entity_id": "Max power", + "power_temp": "Shedding temperature", + "use_power_central_config": "Use central power configuration" + }, + "data_description": { "power_sensor_entity_id": "Power sensor entity id", "max_power_sensor_entity_id": "Max power sensor entity id", - "power_temp": "Temperature for Power shedding" + "power_temp": "Temperature for Power shedding", + "use_power_central_config": "Check to use the central power configuration. Uncheck to use a specific power configuration for this VTherm" } }, "presence": { @@ -153,7 +186,8 @@ "frost_away_temp": "Frost protection preset", "eco_ac_away_temp": "Eco preset in AC mode", "comfort_ac_away_temp": "Comfort preset in AC mode", - "boost_ac_away_temp": "Boost pres et in AC mode" + "boost_ac_away_temp": "Boost pres et in AC mode", + "use_presence_central_config": "Use central presence configuration" }, "data_description": { "presence_sensor_entity_id": "Presence sensor entity id", @@ -163,7 +197,8 @@ "frost_away_temp": "Temperature in Frost protection preset when no presence", "eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode", "comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode", - "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode" + "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode", + "use_presence_central_config": "Check to use the central presence configuration. Uncheck to use a specific presence configuration for this VTherm" } }, "advanced": { @@ -173,20 +208,23 @@ "minimal_activation_delay": "Minimal activation delay", "security_delay_min": "Security delay (in minutes)", "security_min_on_percent": "Minimal power percent to enable security mode", - "security_default_on_percent": "Power percent to use in security mode" + "security_default_on_percent": "Power percent to use in security mode", + "use_advanced_central_config": "Use central advanced configuration" }, "data_description": { "minimal_activation_delay": "Delay in seconds under which the equipment will not be activated", "security_delay_min": "Maximum allowed delay in minutes between two temperature measurements. Above this delay the thermostat will turn to a security off state", "security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of power percent the thermostat won't go into security preset", - "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset" + "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset", + "use_advanced_central_config": "Check to use the central advanced configuration. Uncheck to use a specific advanced configuration for this VTherm" } } }, "error": { "unknown": "Unexpected error", "unknown_entity": "Unknown entity id", - "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both" + "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both", + "no_central_config": "You cannot check 'use central configuration' because no central configuration was found. You need to create a Versatile Thermostat of type 'Central Configuration' to use it." }, "abort": { "already_configured": "Device is already configured" @@ -196,25 +234,39 @@ "flow_title": "Versatile Thermostat configuration", "step": { "user": { - "title": "Add new Versatile Thermostat", + "title": "Type - {name}", + "data": { + "thermostat_type": "Thermostat type" + }, + "data_description": { + "thermostat_type": "Only one central configuration type is possible" + } + }, + "main": { + "title": "{name}", "description": "Main mandatory attributes", "data": { "name": "Name", "thermostat_type": "Thermostat type", - "temperature_sensor_entity_id": "Temperature sensor entity id", - "external_temperature_sensor_entity_id": "External temperature sensor entity id", + "temperature_sensor_entity_id": "Room temperature sensor entity id", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id", "cycle_min": "Cycle duration (minutes)", "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", - "device_power": "Device power (kW)", + "device_power": "Device power", "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", - "use_presence_feature": "Use presence detection" + "use_presence_feature": "Use presence detection", + "use_main_central_config": "Use central main configuration" + }, + "data_description": { + "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific configuration for this VTherm", + "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } }, "type": { - "title": "Linked entities", + "title": "{name}", "description": "Linked entities attributes", "data": { "heater_entity_id": "1st heater switch", @@ -260,11 +312,17 @@ } }, "tpi": { - "title": "TPI", + "title": "{name}", "description": "Time Proportional Integral attributes", "data": { + "tpi_coef_int": "coef_int", + "tpi_coef_ext": "coef_ext", + "use_tpi_central_config": "Use central TPI configuration" + }, + "data_description": { "tpi_coef_int": "Coefficient to use for internal temperature delta", - "tpi_coef_ext": "Coefficient to use for external temperature delta" + "tpi_coef_ext": "Coefficient to use for external temperature delta", + "use_tpi_central_config": "Check to use the central TPI configuration. Uncheck to use a specific TPI configuration for this VTherm" } }, "presets": { @@ -277,7 +335,8 @@ "frost_temp": "Frost protection preset", "eco_ac_temp": "Eco preset for AC mode", "comfort_ac_temp": "Comfort preset for AC mode", - "boost_ac_temp": "Boost preset for AC mode" + "boost_ac_temp": "Boost preset for AC mode", + "use_presets_central_config": "Use central presets configuration" }, "data_description": { "eco_temp": "Temperature in Eco preset", @@ -286,88 +345,115 @@ "frost_temp": "Temperature in Frost protection preset", "eco_ac_temp": "Temperature in Eco preset for AC mode", "comfort_ac_temp": "Temperature in Comfort preset for AC mode", - "boost_ac_temp": "Temperature in Boost preset for AC mode" + "boost_ac_temp": "Temperature in Boost preset for AC mode", + "use_presets_central_config": "Check to use the central presets configuration. Uncheck to use a specific presets configuration for this VTherm" } }, "window": { - "title": "Window management", - "description": "Open window management.\nLeave corresponding entity_id empty if not used\nYou can also configure automatic window open detection based on temperature decrease", + "title": "{name}", + "description": "Open window management.\nYou can also configure automatic window open detection based on temperature decrease", "data": { "window_sensor_entity_id": "Window sensor entity id", "window_delay": "Window sensor delay (seconds)", "window_auto_open_threshold": "Temperature decrease threshold for automatic window open detection (in °/hours)", "window_auto_close_threshold": "Temperature increase threshold for end of automatic detection (in °/hours)", - "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)" + "window_auto_max_duration": "Maximum duration of automatic window open detection (in min)", + "use_window_central_config": "Use central window configuration" }, "data_description": { "window_sensor_entity_id": "Leave empty if no window sensor should be used", "window_delay": "The delay in seconds before sensor detection is taken into account", "window_auto_open_threshold": "Recommended value: between 3 and 10. Leave empty if automatic window open detection is not used", "window_auto_close_threshold": "Recommended value: 0. Leave empty if automatic window open detection is not used", - "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used" + "window_auto_max_duration": "Recommended value: 60 (one hour). Leave empty if automatic window open detection is not used", + "use_window_central_config": "Check to use the central window configuration. Uncheck to use a specific window configuration for this VTherm" } }, "motion": { - "title": "Motion management", - "description": "Motion sensor management. Preset can switch automatically depending of a motion detection\nLeave corresponding entity_id empty if not used.\nmotion_preset and no_motion_preset should be set to the corresponding preset name", + "title": "{name}", + "description": "Motion management. Preset can switch automatically depending of a motion detection\nLeave corresponding entity_id empty if not used.\nmotion_preset and no_motion_preset should be set to the corresponding preset name", "data": { "motion_sensor_entity_id": "Motion sensor entity id", "motion_delay": "Activation delay", "motion_off_delay": "Deactivation delay", "motion_preset": "Motion preset", - "no_motion_preset": "No motion preset" + "no_motion_preset": "No motion preset", + "use_motion_central_config": "Use central motion configuration" }, "data_description": { "motion_sensor_entity_id": "The entity id of the motion sensor", "motion_delay": "Motion activation delay (seconds)", "motion_off_delay": "Motion deactivation delay (seconds)", "motion_preset": "Preset to use when motion is detected", - "no_motion_preset": "Preset to use when no motion is detected" + "no_motion_preset": "Preset to use when no motion is detected", + "use_motion_central_config": "Check to use the central motion configuration. Uncheck to use a specific motion configuration for this VTherm" } }, "power": { - "title": "Power management", + "title": "{name}", "description": "Power management attributes.\nGives the power and max power sensor of your home.\nThen specify the power consumption of the heater when on.\nAll sensors and device power should have the same unit (kW or W).\nLeave corresponding entity_id empty if not used.", "data": { + "power_sensor_entity_id": "Power", + "max_power_sensor_entity_id": "Max power", + "power_temp": "Shedding temperature", + "use_power_central_config": "Use central power configuration" + }, + "data_description": { "power_sensor_entity_id": "Power sensor entity id", "max_power_sensor_entity_id": "Max power sensor entity id", - "power_temp": "Temperature for Power shedding" + "power_temp": "Temperature for Power shedding", + "use_power_central_config": "Check to use the central power configuration. Uncheck to use a specific power configuration for this VTherm" } }, "presence": { - "title": "Presence management", + "title": "{name}", "description": "Presence management attributes.\nGives the a presence sensor of your home (true is someone is present).\nThen specify either the preset to use when presence sensor is false or the offset in temperature to apply.\nIf preset is given, the offset will not be used.\nLeave corresponding entity_id empty if not used.", "data": { + "presence_sensor_entity_id": "Presence sensor", + "eco_away_temp": "Eco away preset", + "comfort_away_temp": "Comfort away preset", + "boost_away_temp": "Boost away preset", + "eco_ac_away_temp": "Eco away preset in AC mode", + "comfort_ac_away_temp": "Comfort away preset in AC mode", + "boost_ac_away_temp": "Boost away preset in AC mode", + "use_presence_central_config": "Use central presence configuration" + }, + "data_description": { "presence_sensor_entity_id": "Presence sensor entity id", "eco_away_temp": "Temperature in Eco preset when no presence", "comfort_away_temp": "Temperature in Comfort preset when no presence", "boost_away_temp": "Temperature in Boost preset when no presence", + "frost_away_temp": "Temperature in Frost protection preset when no presence", "eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode", "comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode", - "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode" + "boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode", + "use_presence_central_config": "Check to use the central presence configuration. Uncheck to use a specific presence configuration for this VTherm" } }, "advanced": { - "title": "Advanced parameters", - "description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThese parameters can lead to very poor temperature control or bad power regulation.", + "title": "{name}", + "description": "Advanced parameters. Leave the default values if you don't know what you are doing.\nThese parameters can lead to very poor temperature control or bad power regulation.", "data": { "minimal_activation_delay": "Minimal activation delay", "security_delay_min": "Security delay (in minutes)", "security_min_on_percent": "Minimal power percent to enable security mode", - "security_default_on_percent": "Power percent to use in security mode" + "security_default_on_percent": "Power percent to use in security mode", + "use_advanced_central_config": "Use central advanced configuration" }, "data_description": { "minimal_activation_delay": "Delay in seconds under which the equipment will not be activated", "security_delay_min": "Maximum allowed delay in minutes between two temperature measurements. Above this delay the thermostat will turn to a security off state", "security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of power percent the thermostat won't go into security preset", - "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset" + "security_default_on_percent": "The default heating power percent value in security preset. Set to 0 to switch off heater in security preset", + "use_advanced_central_config": "Check to use the central advanced configuration. Uncheck to use a specific advanced configuration for this VTherm" } } }, "error": { "unknown": "Unexpected error", "unknown_entity": "Unknown entity id", - "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both" + "window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both", + "no_central_config": "You cannot check 'use central configuration' because no central configuration was found. You need to create a Versatile Thermostat of type 'Central Configuration' to use it." }, "abort": { "already_configured": "Device is already configured" @@ -376,6 +462,7 @@ "selector": { "thermostat_type": { "options": { + "thermostat_central_config": "Central configuration", "thermostat_over_switch": "Thermostat over a switch", "thermostat_over_climate": "Thermostat over a climate", "thermostat_over_valve": "Thermostat over a valve" diff --git a/custom_components/versatile_thermostat/translations/fr.json b/custom_components/versatile_thermostat/translations/fr.json index d574f8c..2198178 100644 --- a/custom_components/versatile_thermostat/translations/fr.json +++ b/custom_components/versatile_thermostat/translations/fr.json @@ -4,6 +4,15 @@ "flow_title": "Versatile Thermostat configuration", "step": { "user": { + "title": "Type du nouveau Versatile Thermostat", + "data": { + "thermostat_type": "Type de thermostat" + }, + "data_description": { + "thermostat_type": "Un seul thermostat de type Configuration centrale est possible." + } + }, + "main": { "title": "Ajout d'un nouveau thermostat", "description": "Principaux attributs obligatoires", "data": { @@ -18,7 +27,12 @@ "use_window_feature": "Avec détection des ouvertures", "use_motion_feature": "Avec détection de mouvement", "use_power_feature": "Avec gestion de la puissance", - "use_presence_feature": "Avec détection de présence" + "use_presence_feature": "Avec détection de présence", + "use_main_central_config": "Utiliser la configuration centrale principale" + }, + "data_description": { + "external_temperature_sensor_entity_id": "Entity id du capteur de température extérieure. N'est pas utilisé si la configuration centrale est utilisée", + "use_main_central_config": "Cochez pour utiliser la configuration centrale principale. Décochez et saisissez les attributs pour utiliser une configuration spécifique principale" } }, "type": { @@ -71,8 +85,14 @@ "title": "TPI", "description": "Attributs de l'algo Time Proportional Integral", "data": { - "tpi_coef_int": "coeff_int : Coefficient à utiliser pour le delta de température interne", - "tpi_coef_ext": "coeff_ext : Coefficient à utiliser pour le delta de température externe" + "tpi_coef_int": "coeff_int", + "tpi_coef_ext": "coeff_ext", + "use_tpi_central_config": "Utiliser la configuration TPI centrale" + }, + "data_description": { + "tpi_coef_int": "Coefficient à utiliser pour le delta de température interne", + "tpi_coef_ext": "Coefficient à utiliser pour le delta de température externe", + "use_tpi_central_config": "Cochez pour utiliser la configuration TPI centrale. Décochez et saisissez les attributs pour utiliser une configuration TPI spécifique" } }, "presets": { @@ -85,7 +105,8 @@ "frost_temp": "Preset Hors-gel", "eco_ac_temp": "Preset Eco en mode AC", "comfort_ac_temp": "Preset Comfort en mode AC", - "boost_ac_temp": "Preset Boost en mode AC" + "boost_ac_temp": "Preset Boost en mode AC", + "use_presets_central_config": "Utiliser la configuration des presets centrale" }, "data_description": { "eco_temp": "Température en preset Eco", @@ -94,7 +115,8 @@ "frost_temp": "Température en preset Hors-gel", "eco_ac_temp": "Température en preset Eco en mode AC", "comfort_ac_temp": "Température en preset Comfort en mode AC", - "boost_ac_temp": "Température en preset Boost en mode AC" + "boost_ac_temp": "Température en preset Boost en mode AC", + "use_presets_central_config": "Cochez pour utiliser la configuration des presets centrale. Décochez et saisissez les attributs pour utiliser une configuration des presets spécifique" } }, "window": { @@ -105,14 +127,16 @@ "window_delay": "Délai avant extinction (secondes)", "window_auto_open_threshold": "Seuil haut de chute de température pour la détection automatique (en °/heure)", "window_auto_close_threshold": "Seuil bas de chute de température pour la fin de détection automatique (en °/heure)", - "window_auto_max_duration": "Durée maximum d'une extinction automatique (en min)" + "window_auto_max_duration": "Durée maximum d'une extinction automatique (en min)", + "use_window_central_config": "Utiliser la configuration centrale des ouvertures" }, "data_description": { "window_sensor_entity_id": "Laissez vide si vous n'avez de détecteur", "window_delay": "Le délai (en secondes) avant que le changement du détecteur soit pris en compte", "window_auto_open_threshold": "Valeur recommandée: entre 3 et 10. Laissez vide si vous n'utilisez pas la détection automatique", "window_auto_close_threshold": "Valeur recommandée: 0. Laissez vide si vous n'utilisez pas la détection automatique", - "window_auto_max_duration": "Valeur recommandée: 60 (1 heure). Laissez vide si vous n'utilisez pas la détection automatique" + "window_auto_max_duration": "Valeur recommandée: 60 (1 heure). Laissez vide si vous n'utilisez pas la détection automatique", + "use_window_central_config": "Cochez pour utiliser la configuration centrale des ouvertures. Décochez et saisissez les attributs pour utiliser une configuration spécifique des ouvertures" } }, "motion": { @@ -123,23 +147,32 @@ "motion_delay": "Délai d'activation", "motion_off_delay": "Délai de désactivation", "motion_preset": "Preset si mouvement", - "no_motion_preset": "Preset si pas de mouvement" + "no_motion_preset": "Preset si pas de mouvement", + "use_motion_central_config": "Utiliser la condfiguration centrale du mouvement" }, "data_description": { "motion_sensor_entity_id": "Détecteur de mouvement entity id", "motion_delay": "Délai avant activation lorsqu'un mouvement est détecté (secondss)", "motion_off_delai": "Délai avant désactivation lorsqu'aucun mouvement n'est détecté (secondes)", "motion_preset": "Preset à utiliser si mouvement détecté", - "no_motion_preset": "Preset à utiliser si pas de mouvement détecté" + "no_motion_preset": "Preset à utiliser si pas de mouvement détecté", + "use_motion_central_config": "Cochez pour utiliser la configuration centrale du mouvement. Décochez et saisissez les attributs pour utiliser une configuration spécifique du mouvement" } }, "power": { - "title": "Gestion de l'énergie", + "title": "Gestion de la puissance", "description": "Sélectionne automatiquement le preset 'power' si la puissance consommée est supérieure à un maximum.\nDonnez les entity id des capteurs qui mesurent la puissance totale et la puissance max autorisée.\nEnsuite donnez la puissance de l'équipement.\nTous les capteurs et la puissance consommée par l'équipement doivent avoir la même unité de mesure (kW ou W).", "data": { "power_sensor_entity_id": "Capteur de puissance totale (entity id)", "max_power_sensor_entity_id": "Capteur de puissance Max (entity id)", - "power_temp": "Température si délestaqe" + "power_temp": "Température si délestaqe", + "use_power_central_config": "Utiliser la configuration centrale de la puissance" + }, + "data_description": { + "power_sensor_entity_id": "Entity id du capteur de puissance totale du logement", + "max_power_sensor_entity_id": "Entity id du capteur de puissance Max autorisée avant délestage", + "power_temp": "Température cible si délestaqe", + "use_power_central_config": "Cochez pour utiliser la configuration centrale de la puissance. Décochez et saisissez les attributs pour utiliser une configuration spécifique de la puissance" } }, "presence": { @@ -153,7 +186,8 @@ "frost_away_temp": "preset Hors-gel", "eco_ac_away_temp": "preset Eco en mode AC", "comfort_ac_away_temp": "preset Comfort en mode AC", - "boost_ac_away_temp": "preset Boost en mode AC" + "boost_ac_away_temp": "preset Boost en mode AC", + "use_presence_central_config": "Utiliser la configuration centrale de la présence" }, "data_description": { "presence_sensor_entity_id": "Capteur de présence entity id (true si quelqu'un est présent)", @@ -163,7 +197,8 @@ "frost_away_temp": "Température en preset Hors-gel en cas d'absence", "eco_ac_away_temp": "Température en preset Eco en cas d'absence en mode AC", "comfort_ac_away_temp": "Température en preset Comfort en cas d'absence en mode AC", - "boost_ac_away_temp": "Température en preset Boost en cas d'absence en mode AC" + "boost_ac_away_temp": "Température en preset Boost en cas d'absence en mode AC", + "use_presence_central_config": "Cochez pour utiliser la configuration centrale de la présence. Décochez et saisissez les attributs pour utiliser une configuration spécifique de la présence" } }, "advanced": { @@ -173,20 +208,23 @@ "minimal_activation_delay": "Délai minimal d'activation", "security_delay_min": "Délai maximal entre 2 mesures de températures", "security_min_on_percent": "Pourcentage minimal de puissance", - "security_default_on_percent": "Pourcentage de puissance a utiliser en mode securité" + "security_default_on_percent": "Pourcentage de puissance a utiliser en mode securité", + "use_advanced_central_config": "Utiliser la configuration centrale avancée" }, "data_description": { "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 de sécurité", "security_min_on_percent": "Seuil minimal de pourcentage de chauffage en-dessous duquel le préréglage sécurité ne sera jamais activé", - "security_default_on_percent": "Valeur par défaut pour le pourcentage de chauffage en mode sécurité. Mettre 0 pour éteindre le radiateur en mode sécurité" + "security_default_on_percent": "Valeur par défaut pour le pourcentage de chauffage en mode sécurité. Mettre 0 pour éteindre le radiateur en mode sécurité", + "use_advanced_central_config": "Cochez pour utiliser la configuration centrale avancée. Décochez et saisissez les attributs pour utiliser une configuration spécifique avancée" } } }, "error": { "unknown": "Erreur inattendue", "unknown_entity": "entity id inconnu", - "window_open_detection_method": "Une seule méthode de détection des ouvertures ouvertes doit être utilisée. Utilisez le détecteur d'ouverture ou les seuils de température mais pas les deux." + "window_open_detection_method": "Une seule méthode de détection des ouvertures ouvertes doit être utilisée. Utilisez le détecteur d'ouverture ou les seuils de température mais pas les deux.", + "no_central_config": "Vous ne pouvez pas cocher 'Utiliser la configuration centrale' car aucune configuration centrale n'a été trouvée. Vous devez créer un Versatile Thermostat de type 'Central Configuration' pour pouvoir l'utiliser." }, "abort": { "already_configured": "Le device est déjà configuré" @@ -196,14 +234,22 @@ "flow_title": "Versatile Thermostat configuration", "step": { "user": { - "title": "Ajout d'un nouveau thermostat", + "title": "Type - {name}", + "data": { + "thermostat_type": "Type de thermostat" + }, + "data_description": { + "thermostat_type": "Un seul thermostat de type Configuration centrale est possible." + } + }, + "main": { + "title": "{name}", "description": "Principaux attributs obligatoires", "data": { "name": "Nom", - "thermostat_over_switch": "Thermostat sur un switch", - "thermostat_over_climate": "Thermostat sur un autre thermostat", + "thermostat_type": "Type de thermostat", "temperature_sensor_entity_id": "Température sensor entity id", - "external_temperature_sensor_entity_id": "Temperature exterieure sensor entity id", + "external_temperature_sensor_entity_id": "Température exterieure sensor entity id", "cycle_min": "Durée du cycle (minutes)", "temp_min": "Température minimale permise", "temp_max": "Température maximale permise", @@ -211,11 +257,16 @@ "use_window_feature": "Avec détection des ouvertures", "use_motion_feature": "Avec détection de mouvement", "use_power_feature": "Avec gestion de la puissance", - "use_presence_feature": "Avec détection de présence" + "use_presence_feature": "Avec détection de présence", + "use_main_central_config": "Utiliser la configuration centrale" + }, + "data_description": { + "use_main_central_config": "Cochez pour utiliser la configuration centrale. Décochez et saisissez les attributs pour utiliser une configuration spécifique", + "external_temperature_sensor_entity_id": "Entity id du capteur de température extérieure. N'est pas utilisé si la configuration centrale est utilisée" } }, "type": { - "title": "Entité(s) liée(s)", + "title": "{name}", "description": "Attributs de(s) l'entité(s) liée(s)", "data": { "heater_entity_id": "1er radiateur", @@ -261,7 +312,7 @@ } }, "tpi": { - "title": "TPI", + "title": "{name}", "description": "Attributs de l'algo Time Proportional Integral", "data": { "tpi_coef_int": "coeff_int : Coefficient à utiliser pour le delta de température interne", @@ -269,8 +320,8 @@ } }, "presets": { - "title": "Presets", - "description": "Pour chaque preset, donnez la température cible (0 pour ignorer le preset)", + "title": "{name}", + "description": "Réglage des presets. Donnez la température cible (0 pour ignorer le preset)", "data": { "eco_temp": "Preset Eco", "comfort_temp": "Preset Comfort", @@ -278,7 +329,8 @@ "frost_temp": "Preset Hors-gel", "eco_ac_temp": "Preset Eco en mode AC", "comfort_ac_temp": "Preset Comfort en mode AC", - "boost_ac_temp": "Preset Boost en mode AC" + "boost_ac_temp": "Preset Boost en mode AC", + "use_presets_central_config": "Utiliser la configuration des presets centrale" }, "data_description": { "eco_temp": "Température en preset Eco", @@ -287,57 +339,69 @@ "frost_temp": "Température en preset Hors-gel", "eco_ac_temp": "Température en preset Eco en mode AC", "comfort_ac_temp": "Température en preset Comfort en mode AC", - "boost_ac_temp": "Température en preset Boost en mode AC" + "boost_ac_temp": "Température en preset Boost en mode AC", + "use_presets_central_config": "Cochez pour utiliser la configuration des presets centrale. Décochez et saisissez les attributs pour utiliser une configuration des presets spécifique" } }, "window": { - "title": "Gestion d'une ouverture", - "description": "Coupe le radiateur si l'ouverture est ouverte.\nLaissez l'entity id vide si non utilisé.", + "title": "{name}", + "description": "Gestion des ouvertures. Coupe le radiateur si l'ouverture est ouverte.", "data": { "window_sensor_entity_id": "Détecteur d'ouverture (entity id)", "window_delay": "Délai avant extinction (secondes)", "window_auto_open_threshold": "Seuil haut de chute de température pour la détection automatique (en °/heure)", "window_auto_close_threshold": "Seuil bas de chute de température pour la fin de détection automatique (en °/heure)", - "window_auto_max_duration": "Durée maximum d'une extinction automatique (en min)" + "window_auto_max_duration": "Durée maximum d'une extinction automatique (en min)", + "use_window_central_config": "Utiliser la configuration centrale des ouvertures" }, "data_description": { "window_sensor_entity_id": "Laissez vide si vous n'avez de détecteur", "window_delay": "Le délai (en secondes) avant que le changement du détecteur soit pris en compte", "window_auto_open_threshold": "Valeur recommandée: entre 3 et 10. Laissez vide si vous n'utilisez pas la détection automatique", "window_auto_close_threshold": "Valeur recommandée: 0. Laissez vide si vous n'utilisez pas la détection automatique", - "window_auto_max_duration": "Valeur recommandée: 60 (1 heure). Laissez vide si vous n'utilisez pas la détection automatique" + "window_auto_max_duration": "Valeur recommandée: 60 (1 heure). Laissez vide si vous n'utilisez pas la détection automatique", + "use_window_central_config": "Cochez pour utiliser la configuration centrale des ouvertures. Décochez et saisissez les attributs pour utiliser une configuration spécifique des ouvertures" } }, "motion": { - "title": "Gestion de la détection de mouvement", - "description": "Le preset s'ajuste automatiquement si un mouvement est détecté\nLaissez l'entity id vide si non utilisé.\n'Preset mouvement' et 'Preset sans mouvement' doivent être choisis avec les preset à utiliser.", + "title": "{name}", + "description": "Gestion du mouvement. Le preset s'ajuste automatiquement si un mouvement est détecté\n'Preset mouvement' et 'Preset sans mouvement' doivent être choisis avec les preset à utiliser.", "data": { "motion_sensor_entity_id": "Détecteur de mouvement", "motion_delay": "Délai d'activation", "motion_off_delay": "Délai de désactivation", "motion_preset": "Preset si mouvement", - "no_motion_preset": "Preset si pas de mouvement" + "no_motion_preset": "Preset si pas de mouvement", + "use_motion_central_config": "Utiliser la condfiguration centrale du mouvement" }, "data_description": { "motion_sensor_entity_id": "Détecteur de mouvement entity id", "motion_delay": "Délai avant activation lorsqu'un mouvement est détecté (secondss)", "motion_off_delai": "Délai avant désactivation lorsqu'aucun mouvement n'est détecté (secondes)", "motion_preset": "Preset à utiliser si mouvement détecté", - "no_motion_preset": "Preset à utiliser si pas de mouvement détecté" + "no_motion_preset": "Preset à utiliser si pas de mouvement détecté", + "use_motion_central_config": "Cochez pour utiliser la configuration centrale du mouvement. Décochez et saisissez les attributs pour utiliser une configuration spécifique du mouvement" } }, "power": { - "title": "Gestion de l'énergie", - "description": "Sélectionne automatiquement le preset 'power' si la puissance consommée est supérieure à un maximum.\nDonnez les entity id des capteurs qui mesurent la puissance totale et la puissance max autorisée.\nEnsuite donnez la puissance de l'équipement.\nTous les capteurs et la puissance consommée par l'équipement doivent avoir la même unité de mesure (kW ou W).", + "title": "{name}", + "description": "Gestion de la puissance. Sélectionne automatiquement le preset 'power' si la puissance consommée est supérieure à un maximum. Tous les capteurs et la puissance consommée par l'équipement doivent avoir la même unité de mesure (kW ou W).", "data": { - "power_sensor_entity_id": "Capteur de puissance totale (entity id)", + "power_sensor_entity_id": "Puissance totale", "max_power_sensor_entity_id": "Capteur de puissance Max (entity id)", - "power_temp": "Température si délestaqe" + "power_temp": "Température si délestaqe", + "use_power_central_config": "Utiliser la configuration centrale de la puissance" + }, + "data_description": { + "power_sensor_entity_id": "Entity id du capteur de puissance totale du logement", + "max_power_sensor_entity_id": "Entity id du capteur de puissance Max autorisée avant délestage", + "power_temp": "Température cible si délestaqe", + "use_power_central_config": "Cochez pour utiliser la configuration centrale de la puissance. Décochez et saisissez les attributs pour utiliser une configuration spécifique de la puissance" } }, "presence": { - "title": "Gestion de la présence", - "description": "Donnez un capteur de présence (true si quelqu'un est présent).\nEnsuite spécifiez soit un preset à utiliser, soit un offset de température à appliquer lorsque personne n'est présent.\nSi le préset est utilisé, l'offset ne sera pas pris en compte.\nLaissez l'entity id vide si la gestion de la présence est non utilisée.", + "title": "{name}", + "description": "Gestion de la présence. Le capteur de présence doit être true ou home si quelqu'un est présent.", "data": { "presence_sensor_entity_id": "Capteur de présence", "eco_away_temp": "preset Eco", @@ -346,7 +410,8 @@ "frost_away_temp": "preset Hors-gel", "eco_ac_away_temp": "preset Eco en mode AC", "comfort_ac_away_temp": "preset Comfort en mode AC", - "boost_ac_away_temp": "preset Boost en mode AC" + "boost_ac_away_temp": "preset Boost en mode AC", + "use_presence_central_config": "Utiliser la configuration centrale de la présence" }, "data_description": { "presence_sensor_entity_id": "Capteur de présence entity id (true si quelqu'un est présent)", @@ -356,30 +421,34 @@ "frost_away_temp": "Température en preset Hors-gel en cas d'absence", "eco_ac_away_temp": "Température en preset Eco en cas d'absence en mode AC", "comfort_ac_away_temp": "Température en preset Comfort en cas d'absence en mode AC", - "boost_ac_away_temp": "Température en preset Boost en cas d'absence en mode AC" + "boost_ac_away_temp": "Température en preset Boost en cas d'absence en mode AC", + "use_presence_central_config": "Cochez pour utiliser la configuration centrale de la présence. Décochez et saisissez les attributs pour utiliser une configuration spécifique de la présence" } }, "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.", + "title": "{name}", + "description": "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 minimal d'activation", "security_delay_min": "Délai maximal entre 2 mesures de températures", "security_min_on_percent": "Pourcentage minimal de puissance", - "security_default_on_percent": "Pourcentage de puissance a utiliser en mode securité" + "security_default_on_percent": "Pourcentage de puissance a utiliser en mode securité", + "use_advanced_central_config": "Utiliser la configuration centrale avancée" }, "data_description": { "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 de sécurité", "security_min_on_percent": "Seuil minimal de pourcentage de chauffage en-dessous duquel le préréglage sécurité ne sera jamais activé", - "security_default_on_percent": "Valeur par défaut pour le pourcentage de chauffage en mode sécurité. Mettre 0 pour éteindre le radiateur en mode sécurité" + "security_default_on_percent": "Valeur par défaut pour le pourcentage de chauffage en mode sécurité. Mettre 0 pour éteindre le radiateur en mode sécurité", + "use_advanced_central_config": "Cochez pour utiliser la configuration centrale avancée. Décochez et saisissez les attributs pour utiliser une configuration spécifique avancée" } } }, "error": { "unknown": "Erreur inattendue", "unknown_entity": "entity id inconnu", - "window_open_detection_method": "Une seule méthode de détection des ouvertures ouvertes doit être utilisée. Utilisez le détecteur d'ouverture ou les seuils de température mais pas les deux." + "window_open_detection_method": "Une seule méthode de détection des ouvertures ouvertes doit être utilisée. Utilisez le détecteur d'ouverture ou les seuils de température mais pas les deux.", + "no_central_config": "Vous ne pouvez pas cocher 'Utiliser la configuration centrale' car aucune configuration centrale n'a été trouvée. Vous devez créer un Versatile Thermostat de type 'Central Configuration' pour pouvoir l'utiliser." }, "abort": { "already_configured": "Le device est déjà configuré" @@ -388,6 +457,7 @@ "selector": { "thermostat_type": { "options": { + "thermostat_central_config": "Configuration centrale", "thermostat_over_switch": "Thermostat sur un switch", "thermostat_over_climate": "Thermostat sur un autre thermostat", "thermostat_over_valve": "Thermostat sur une valve" diff --git a/custom_components/versatile_thermostat/vtherm_api.py b/custom_components/versatile_thermostat/vtherm_api.py index 2a26c6b..ee7be72 100644 --- a/custom_components/versatile_thermostat/vtherm_api.py +++ b/custom_components/versatile_thermostat/vtherm_api.py @@ -3,7 +3,13 @@ import logging from homeassistant.core import HomeAssistant from homeassistant.config_entries import ConfigEntry -from .const import DOMAIN, CONF_AUTO_REGULATION_EXPERT, CONF_SHORT_EMA_PARAMS +from .const import ( + DOMAIN, + CONF_AUTO_REGULATION_EXPERT, + CONF_SHORT_EMA_PARAMS, + CONF_THERMOSTAT_TYPE, + CONF_THERMOSTAT_CENTRAL_CONFIG, +) VTHERM_API_NAME = "vtherm_api" @@ -17,37 +23,56 @@ class VersatileThermostatAPI(dict): # _entries: Dict(str, ConfigEntry) @classmethod - def get_vtherm_api(cls, hass: HomeAssistant): + def get_vtherm_api(cls, hass=None): """Get the eventual VTherm API class instance""" - ret = hass.data.get(DOMAIN).get(VTHERM_API_NAME) + if hass is not None: + VersatileThermostatAPI._hass = hass + else: + if VersatileThermostatAPI._hass is None: + return None + + ret = VersatileThermostatAPI._hass.data.get(DOMAIN).get(VTHERM_API_NAME) if ret is None: - ret = VersatileThermostatAPI(hass) + ret = VersatileThermostatAPI() hass.data[DOMAIN][VTHERM_API_NAME] = ret return ret - def __init__(self, hass: HomeAssistant) -> None: + def __init__(self) -> None: _LOGGER.debug("building a VersatileThermostatAPI") super().__init__() - self._hass = hass self._expert_params = None self._short_ema_params = None + self._central_config = None + + def find_central_configuration(self): + """Search for a central configuration""" + for config_entry in VersatileThermostatAPI._hass.config_entries.async_entries( + DOMAIN + ): + if ( + config_entry.data.get(CONF_THERMOSTAT_TYPE) + == CONF_THERMOSTAT_CENTRAL_CONFIG + ): + self._central_config = config_entry + return self._central_config + return None def add_entry(self, entry: ConfigEntry): """Add a new entry""" _LOGGER.debug("Add the entry %s", entry.entry_id) # self._entries[entry.entry_id] = entry # Add the entry in hass.data - self._hass.data[DOMAIN][entry.entry_id] = entry + VersatileThermostatAPI._hass.data[DOMAIN][entry.entry_id] = entry def remove_entry(self, entry: ConfigEntry): """Remove an entry""" _LOGGER.debug("Remove the entry %s", entry.entry_id) # self._entries.pop(entry.entry_id) - self._hass.data[DOMAIN].pop(entry.entry_id) + VersatileThermostatAPI._hass.data[DOMAIN].pop(entry.entry_id) # If not more entries are preset, remove the API if len(self) == 0: _LOGGER.debug("No more entries-> Remove the API from DOMAIN") - self._hass.data.pop(DOMAIN) + VersatileThermostatAPI._hass.data.pop(DOMAIN) def set_global_config(self, config): """Read the global configuration from configuration.yaml file""" @@ -74,4 +99,4 @@ class VersatileThermostatAPI(dict): @property def hass(self): """Get the HomeAssistant object""" - return self._hass + return VersatileThermostatAPI._hass