mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Thermostat remove deprecated config (#3643)
* Raise errors for all the now deprecated options * Fix CONF_DEFAULT_PRESET detection * Stop attempting to set the non-existent normal_config * Add support for default presets * Fix correct detection of Two Point temperature mode * Fix lint issues * Fix tests * Generate correct yaml for equivalent configurations * Remove debug code * Only set default preset if the thermostat does not have state to restore * Add restore_default_preset_on_boot option If set to True then the default_preset will be applied on every boot. If False (Default) state will be restored from memory as per prior versions * Apply lint suggestions * Switch from restore_default_preset_on_boot to an enum for startup_behavior This gives better self-documentation as well as the option for extending to other options down the track * Lint fixes * Rename startup_behavior to on_boot_restore_from This removes any issues with different English locales * Fix comparable_preset yaml output alignment * Add dump of on_boot_restore_from setting Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
		| @@ -69,6 +69,8 @@ from esphome.const import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| CONF_PRESET_CHANGE = "preset_change" | CONF_PRESET_CHANGE = "preset_change" | ||||||
|  | CONF_DEFAULT_PRESET = "default_preset" | ||||||
|  | CONF_ON_BOOT_RESTORE_FROM = "on_boot_restore_from" | ||||||
|  |  | ||||||
| CODEOWNERS = ["@kbx81"] | CODEOWNERS = ["@kbx81"] | ||||||
|  |  | ||||||
| @@ -80,6 +82,13 @@ ThermostatClimate = thermostat_ns.class_( | |||||||
| ThermostatClimateTargetTempConfig = thermostat_ns.struct( | ThermostatClimateTargetTempConfig = thermostat_ns.struct( | ||||||
|     "ThermostatClimateTargetTempConfig" |     "ThermostatClimateTargetTempConfig" | ||||||
| ) | ) | ||||||
|  | OnBootRestoreFrom = thermostat_ns.enum("OnBootRestoreFrom") | ||||||
|  | ON_BOOT_RESTORE_FROM = { | ||||||
|  |     "MEMORY": OnBootRestoreFrom.MEMORY, | ||||||
|  |     "DEFAULT_PRESET": OnBootRestoreFrom.DEFAULT_PRESET, | ||||||
|  | } | ||||||
|  | validate_on_boot_restore_from = cv.enum(ON_BOOT_RESTORE_FROM, upper=True) | ||||||
|  |  | ||||||
| ClimateMode = climate_ns.enum("ClimateMode") | ClimateMode = climate_ns.enum("ClimateMode") | ||||||
| CLIMATE_MODES = { | CLIMATE_MODES = { | ||||||
|     "OFF": ClimateMode.CLIMATE_MODE_OFF, |     "OFF": ClimateMode.CLIMATE_MODE_OFF, | ||||||
| @@ -125,6 +134,17 @@ def validate_temperature_preset(preset, root_config, name, requirements): | |||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def generate_comparable_preset(config, name): | ||||||
|  |     comparable_preset = f"{CONF_PRESET}:\n" f"  -  {CONF_NAME}: {name}\n" | ||||||
|  |  | ||||||
|  |     if CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config: | ||||||
|  |         comparable_preset += f"     {CONF_DEFAULT_TARGET_TEMPERATURE_LOW}: {config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW]}\n" | ||||||
|  |     if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config: | ||||||
|  |         comparable_preset += f"     {CONF_DEFAULT_TARGET_TEMPERATURE_HIGH}: {config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]}\n" | ||||||
|  |  | ||||||
|  |     return comparable_preset | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_thermostat(config): | def validate_thermostat(config): | ||||||
|     # verify corresponding action(s) exist(s) for any defined climate mode or action |     # verify corresponding action(s) exist(s) for any defined climate mode or action | ||||||
|     requirements = { |     requirements = { | ||||||
| @@ -277,13 +297,32 @@ def validate_thermostat(config): | |||||||
|             CONF_DEFAULT_TARGET_TEMPERATURE_LOW: [CONF_HEAT_ACTION], |             CONF_DEFAULT_TARGET_TEMPERATURE_LOW: [CONF_HEAT_ACTION], | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     # Validate temperature requirements for default configuraation |     # Legacy high/low configs | ||||||
|     validate_temperature_preset(config, config, "default", requirements) |     if CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config: | ||||||
|  |         comparable_preset = generate_comparable_preset(config, "Your new preset") | ||||||
|  |  | ||||||
|     # Validate temperature requirements for away configuration |         raise cv.Invalid( | ||||||
|  |             f"{CONF_DEFAULT_TARGET_TEMPERATURE_LOW} is no longer valid. Please switch to using a preset for an equivalent experience.\nEquivalent configuration:\n\n" | ||||||
|  |             f"{comparable_preset}" | ||||||
|  |         ) | ||||||
|  |     if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config: | ||||||
|  |         comparable_preset = generate_comparable_preset(config, "Your new preset") | ||||||
|  |  | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             f"{CONF_DEFAULT_TARGET_TEMPERATURE_HIGH} is no longer valid. Please switch to using a preset for an equivalent experience.\nEquivalent configuration:\n\n" | ||||||
|  |             f"{comparable_preset}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     # Legacy away mode - raise an error instructing the user to switch to presets | ||||||
|     if CONF_AWAY_CONFIG in config: |     if CONF_AWAY_CONFIG in config: | ||||||
|         away = config[CONF_AWAY_CONFIG] |         comparable_preset = generate_comparable_preset(config[CONF_AWAY_CONFIG], "Away") | ||||||
|         validate_temperature_preset(away, config, "away", requirements) |  | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             f"{CONF_AWAY_CONFIG} is no longer valid. Please switch to using a preset named " | ||||||
|  |             "Away" | ||||||
|  |             " for an equivalent experience.\nEquivalent configuration:\n\n" | ||||||
|  |             f"{comparable_preset}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|     # Validate temperature requirements for presets |     # Validate temperature requirements for presets | ||||||
|     if CONF_PRESET in config: |     if CONF_PRESET in config: | ||||||
| @@ -292,7 +331,12 @@ def validate_thermostat(config): | |||||||
|                 preset_config, config, preset_config[CONF_NAME], requirements |                 preset_config, config, preset_config[CONF_NAME], requirements | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|     # Verify default climate mode is valid given above configuration |     # Warn about using the removed CONF_DEFAULT_MODE and advise users | ||||||
|  |     if CONF_DEFAULT_MODE in config and config[CONF_DEFAULT_MODE] is not None: | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             f"{CONF_DEFAULT_MODE} is no longer valid. Please switch to using presets and specify a {CONF_DEFAULT_PRESET}." | ||||||
|  |         ) | ||||||
|  |  | ||||||
|     default_mode = config[CONF_DEFAULT_MODE] |     default_mode = config[CONF_DEFAULT_MODE] | ||||||
|     requirements = { |     requirements = { | ||||||
|         "HEAT_COOL": [CONF_COOL_ACTION, CONF_HEAT_ACTION], |         "HEAT_COOL": [CONF_COOL_ACTION, CONF_HEAT_ACTION], | ||||||
| @@ -403,6 +447,38 @@ def validate_thermostat(config): | |||||||
|                         f"{CONF_SWING_MODE} is set to {swing_mode} for {preset_config[CONF_NAME]} but {req} is not present in the configuration" |                         f"{CONF_SWING_MODE} is set to {swing_mode} for {preset_config[CONF_NAME]} but {req} is not present in the configuration" | ||||||
|                     ) |                     ) | ||||||
|  |  | ||||||
|  |     # If a default preset is requested then ensure that preset is defined | ||||||
|  |     if CONF_DEFAULT_PRESET in config: | ||||||
|  |         default_preset = config[CONF_DEFAULT_PRESET] | ||||||
|  |  | ||||||
|  |         if CONF_PRESET not in config: | ||||||
|  |             raise cv.Invalid( | ||||||
|  |                 f"{CONF_DEFAULT_PRESET} is specified but no presets are defined" | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         presets = config[CONF_PRESET] | ||||||
|  |         found_preset = False | ||||||
|  |  | ||||||
|  |         for preset in presets: | ||||||
|  |             if preset[CONF_NAME] == default_preset: | ||||||
|  |                 found_preset = True | ||||||
|  |                 break | ||||||
|  |  | ||||||
|  |         if found_preset is False: | ||||||
|  |             raise cv.Invalid( | ||||||
|  |                 f"{CONF_DEFAULT_PRESET} set to '{default_preset}' but no such preset has been defined. Available presets: {[preset[CONF_NAME] for preset in presets]}" | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |     # If restoring default preset on boot is true then ensure we have a default preset | ||||||
|  |     if ( | ||||||
|  |         CONF_ON_BOOT_RESTORE_FROM in config | ||||||
|  |         and config[CONF_ON_BOOT_RESTORE_FROM] is OnBootRestoreFrom.DEFAULT_PRESET | ||||||
|  |     ): | ||||||
|  |         if CONF_DEFAULT_PRESET not in config: | ||||||
|  |             raise cv.Invalid( | ||||||
|  |                 f"{CONF_DEFAULT_PRESET} must be defined to use {CONF_ON_BOOT_RESTORE_FROM} in DEFAULT_PRESET mode" | ||||||
|  |             ) | ||||||
|  |  | ||||||
|     if config[CONF_FAN_WITH_COOLING] is True and CONF_FAN_ONLY_ACTION not in config: |     if config[CONF_FAN_WITH_COOLING] is True and CONF_FAN_ONLY_ACTION not in config: | ||||||
|         raise cv.Invalid( |         raise cv.Invalid( | ||||||
|             f"{CONF_FAN_ONLY_ACTION} must be defined to use {CONF_FAN_WITH_COOLING}" |             f"{CONF_FAN_ONLY_ACTION} must be defined to use {CONF_FAN_WITH_COOLING}" | ||||||
| @@ -502,9 +578,8 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Optional( |             cv.Optional( | ||||||
|                 CONF_TARGET_TEMPERATURE_CHANGE_ACTION |                 CONF_TARGET_TEMPERATURE_CHANGE_ACTION | ||||||
|             ): automation.validate_automation(single=True), |             ): automation.validate_automation(single=True), | ||||||
|             cv.Optional(CONF_DEFAULT_MODE, default="OFF"): cv.templatable( |             cv.Optional(CONF_DEFAULT_MODE, default=None): cv.valid, | ||||||
|                 validate_climate_mode |             cv.Optional(CONF_DEFAULT_PRESET): cv.templatable(cv.string), | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature, |             cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature, | ||||||
|             cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature, |             cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature, | ||||||
|             cv.Optional( |             cv.Optional( | ||||||
| @@ -542,6 +617,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|                 } |                 } | ||||||
|             ), |             ), | ||||||
|             cv.Optional(CONF_PRESET): cv.ensure_list(PRESET_CONFIG_SCHEMA), |             cv.Optional(CONF_PRESET): cv.ensure_list(PRESET_CONFIG_SCHEMA), | ||||||
|  |             cv.Optional(CONF_ON_BOOT_RESTORE_FROM): validate_on_boot_restore_from, | ||||||
|             cv.Optional(CONF_PRESET_CHANGE): automation.validate_automation( |             cv.Optional(CONF_PRESET_CHANGE): automation.validate_automation( | ||||||
|                 single=True |                 single=True | ||||||
|             ), |             ), | ||||||
| @@ -564,9 +640,10 @@ async def to_code(config): | |||||||
|         CONF_COOL_ACTION in config |         CONF_COOL_ACTION in config | ||||||
|         or (config[CONF_FAN_ONLY_COOLING] and CONF_FAN_ONLY_ACTION in config) |         or (config[CONF_FAN_ONLY_COOLING] and CONF_FAN_ONLY_ACTION in config) | ||||||
|     ) |     ) | ||||||
|  |     if two_points_available: | ||||||
|  |         cg.add(var.set_supports_two_points(True)) | ||||||
|  |  | ||||||
|     sens = await cg.get_variable(config[CONF_SENSOR]) |     sens = await cg.get_variable(config[CONF_SENSOR]) | ||||||
|     cg.add(var.set_default_mode(config[CONF_DEFAULT_MODE])) |  | ||||||
|     cg.add( |     cg.add( | ||||||
|         var.set_set_point_minimum_differential( |         var.set_set_point_minimum_differential( | ||||||
|             config[CONF_SET_POINT_MINIMUM_DIFFERENTIAL] |             config[CONF_SET_POINT_MINIMUM_DIFFERENTIAL] | ||||||
| @@ -579,23 +656,6 @@ async def to_code(config): | |||||||
|     cg.add(var.set_heat_deadband(config[CONF_HEAT_DEADBAND])) |     cg.add(var.set_heat_deadband(config[CONF_HEAT_DEADBAND])) | ||||||
|     cg.add(var.set_heat_overrun(config[CONF_HEAT_OVERRUN])) |     cg.add(var.set_heat_overrun(config[CONF_HEAT_OVERRUN])) | ||||||
|  |  | ||||||
|     if two_points_available is True: |  | ||||||
|         cg.add(var.set_supports_two_points(True)) |  | ||||||
|         normal_config = ThermostatClimateTargetTempConfig( |  | ||||||
|             config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW], |  | ||||||
|             config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH], |  | ||||||
|         ) |  | ||||||
|     elif CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config: |  | ||||||
|         cg.add(var.set_supports_two_points(False)) |  | ||||||
|         normal_config = ThermostatClimateTargetTempConfig( |  | ||||||
|             config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH] |  | ||||||
|         ) |  | ||||||
|     elif CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config: |  | ||||||
|         cg.add(var.set_supports_two_points(False)) |  | ||||||
|         normal_config = ThermostatClimateTargetTempConfig( |  | ||||||
|             config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW] |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     if CONF_MAX_COOLING_RUN_TIME in config: |     if CONF_MAX_COOLING_RUN_TIME in config: | ||||||
|         cg.add( |         cg.add( | ||||||
|             var.set_cooling_maximum_run_time_in_sec(config[CONF_MAX_COOLING_RUN_TIME]) |             var.set_cooling_maximum_run_time_in_sec(config[CONF_MAX_COOLING_RUN_TIME]) | ||||||
| @@ -661,7 +721,6 @@ async def to_code(config): | |||||||
|     cg.add(var.set_supports_fan_with_heating(config[CONF_FAN_WITH_HEATING])) |     cg.add(var.set_supports_fan_with_heating(config[CONF_FAN_WITH_HEATING])) | ||||||
|  |  | ||||||
|     cg.add(var.set_use_startup_delay(config[CONF_STARTUP_DELAY])) |     cg.add(var.set_use_startup_delay(config[CONF_STARTUP_DELAY])) | ||||||
|     cg.add(var.set_preset_config(ClimatePreset.CLIMATE_PRESET_HOME, normal_config)) |  | ||||||
|  |  | ||||||
|     await automation.build_automation( |     await automation.build_automation( | ||||||
|         var.get_idle_action_trigger(), [], config[CONF_IDLE_ACTION] |         var.get_idle_action_trigger(), [], config[CONF_IDLE_ACTION] | ||||||
| @@ -808,27 +867,8 @@ async def to_code(config): | |||||||
|             config[CONF_TARGET_TEMPERATURE_CHANGE_ACTION], |             config[CONF_TARGET_TEMPERATURE_CHANGE_ACTION], | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|     if CONF_AWAY_CONFIG in config: |  | ||||||
|         away = config[CONF_AWAY_CONFIG] |  | ||||||
|  |  | ||||||
|         if two_points_available is True: |  | ||||||
|             away_config = ThermostatClimateTargetTempConfig( |  | ||||||
|                 away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW], |  | ||||||
|                 away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH], |  | ||||||
|             ) |  | ||||||
|         elif CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in away: |  | ||||||
|             away_config = ThermostatClimateTargetTempConfig( |  | ||||||
|                 away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH] |  | ||||||
|             ) |  | ||||||
|         elif CONF_DEFAULT_TARGET_TEMPERATURE_LOW in away: |  | ||||||
|             away_config = ThermostatClimateTargetTempConfig( |  | ||||||
|                 away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW] |  | ||||||
|             ) |  | ||||||
|         cg.add(var.set_preset_config(ClimatePreset.CLIMATE_PRESET_AWAY, away_config)) |  | ||||||
|  |  | ||||||
|     if CONF_PRESET in config: |     if CONF_PRESET in config: | ||||||
|         for preset_config in config[CONF_PRESET]: |         for preset_config in config[CONF_PRESET]: | ||||||
|  |  | ||||||
|             name = preset_config[CONF_NAME] |             name = preset_config[CONF_NAME] | ||||||
|             standard_preset = None |             standard_preset = None | ||||||
|             if name.upper() in climate.CLIMATE_PRESETS: |             if name.upper() in climate.CLIMATE_PRESETS: | ||||||
| @@ -872,6 +912,19 @@ async def to_code(config): | |||||||
|             else: |             else: | ||||||
|                 cg.add(var.set_custom_preset_config(name, preset_target_variable)) |                 cg.add(var.set_custom_preset_config(name, preset_target_variable)) | ||||||
|  |  | ||||||
|  |     if CONF_DEFAULT_PRESET in config: | ||||||
|  |         default_preset_name = config[CONF_DEFAULT_PRESET] | ||||||
|  |  | ||||||
|  |         # if the name is a built in preset use the appropriate naming format | ||||||
|  |         if default_preset_name.upper() in climate.CLIMATE_PRESETS: | ||||||
|  |             climate_preset = climate.CLIMATE_PRESETS[default_preset_name.upper()] | ||||||
|  |             cg.add(var.set_default_preset(climate_preset)) | ||||||
|  |         else: | ||||||
|  |             cg.add(var.set_default_preset(default_preset_name)) | ||||||
|  |  | ||||||
|  |     if CONF_ON_BOOT_RESTORE_FROM in config: | ||||||
|  |         cg.add(var.set_on_boot_restore_from(config[CONF_ON_BOOT_RESTORE_FROM])) | ||||||
|  |  | ||||||
|     if CONF_PRESET_CHANGE in config: |     if CONF_PRESET_CHANGE in config: | ||||||
|         await automation.build_automation( |         await automation.build_automation( | ||||||
|             var.get_preset_change_trigger(), [], config[CONF_PRESET_CHANGE] |             var.get_preset_change_trigger(), [], config[CONF_PRESET_CHANGE] | ||||||
|   | |||||||
| @@ -25,15 +25,27 @@ void ThermostatClimate::setup() { | |||||||
|     this->publish_state(); |     this->publish_state(); | ||||||
|   }); |   }); | ||||||
|   this->current_temperature = this->sensor_->state; |   this->current_temperature = this->sensor_->state; | ||||||
|   // restore all climate data, if possible |  | ||||||
|   auto restore = this->restore_state_(); |   auto use_default_preset = true; | ||||||
|   if (restore.has_value()) { |  | ||||||
|     restore->to_call(this).perform(); |   if (this->on_boot_restore_from_ == thermostat::OnBootRestoreFrom::MEMORY) { | ||||||
|   } else { |     // restore all climate data, if possible | ||||||
|     // restore from defaults, change_away handles temps for us |     auto restore = this->restore_state_(); | ||||||
|     this->mode = this->default_mode_; |     if (restore.has_value()) { | ||||||
|     this->change_preset_(climate::CLIMATE_PRESET_HOME); |       use_default_preset = false; | ||||||
|  |       restore->to_call(this).perform(); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // Either we failed to restore state or the user has requested we always apply the default preset | ||||||
|  |   if (use_default_preset) { | ||||||
|  |     if (this->default_preset_ != climate::ClimatePreset::CLIMATE_PRESET_NONE) { | ||||||
|  |       this->change_preset_(this->default_preset_); | ||||||
|  |     } else if (!this->default_custom_preset_.empty()) { | ||||||
|  |       this->change_custom_preset_(this->default_custom_preset_); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // refresh the climate action based on the restored settings, we'll publish_state() later |   // refresh the climate action based on the restored settings, we'll publish_state() later | ||||||
|   this->switch_to_action_(this->compute_action_(), false); |   this->switch_to_action_(this->compute_action_(), false); | ||||||
|   this->switch_to_supplemental_action_(this->compute_supplemental_action_()); |   this->switch_to_supplemental_action_(this->compute_supplemental_action_()); | ||||||
| @@ -923,10 +935,12 @@ bool ThermostatClimate::supplemental_heating_required_() { | |||||||
|           (this->supplemental_action_ == climate::CLIMATE_ACTION_HEATING)); |           (this->supplemental_action_ == climate::CLIMATE_ACTION_HEATING)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ThermostatClimate::dump_preset_config_(const std::string &preset, | void ThermostatClimate::dump_preset_config_(const std::string &preset, const ThermostatClimateTargetTempConfig &config, | ||||||
|                                             const ThermostatClimateTargetTempConfig &config) { |                                             bool is_default_preset) { | ||||||
|   const auto *preset_name = preset.c_str(); |   const auto *preset_name = preset.c_str(); | ||||||
|  |  | ||||||
|  |   ESP_LOGCONFIG(TAG, "      %s Is Default: %s", preset_name, YESNO(is_default_preset)); | ||||||
|  |  | ||||||
|   if (this->supports_heat_) { |   if (this->supports_heat_) { | ||||||
|     if (this->supports_two_points_) { |     if (this->supports_two_points_) { | ||||||
|       ESP_LOGCONFIG(TAG, "      %s Default Target Temperature Low: %.1f°C", preset_name, |       ESP_LOGCONFIG(TAG, "      %s Default Target Temperature Low: %.1f°C", preset_name, | ||||||
| @@ -1061,7 +1075,15 @@ ThermostatClimate::ThermostatClimate() | |||||||
|       temperature_change_trigger_(new Trigger<>()), |       temperature_change_trigger_(new Trigger<>()), | ||||||
|       preset_change_trigger_(new Trigger<>()) {} |       preset_change_trigger_(new Trigger<>()) {} | ||||||
|  |  | ||||||
| void ThermostatClimate::set_default_mode(climate::ClimateMode default_mode) { this->default_mode_ = default_mode; } | void ThermostatClimate::set_default_preset(const std::string &custom_preset) { | ||||||
|  |   this->default_custom_preset_ = custom_preset; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ThermostatClimate::set_default_preset(climate::ClimatePreset preset) { this->default_preset_ = preset; } | ||||||
|  |  | ||||||
|  | void ThermostatClimate::set_on_boot_restore_from(thermostat::OnBootRestoreFrom on_boot_restore_from) { | ||||||
|  |   this->on_boot_restore_from_ = on_boot_restore_from; | ||||||
|  | } | ||||||
| void ThermostatClimate::set_set_point_minimum_differential(float differential) { | void ThermostatClimate::set_set_point_minimum_differential(float differential) { | ||||||
|   this->set_point_minimum_differential_ = differential; |   this->set_point_minimum_differential_ = differential; | ||||||
| } | } | ||||||
| @@ -1213,8 +1235,9 @@ Trigger<> *ThermostatClimate::get_preset_change_trigger() const { return this->p | |||||||
| void ThermostatClimate::dump_config() { | void ThermostatClimate::dump_config() { | ||||||
|   LOG_CLIMATE("", "Thermostat", this); |   LOG_CLIMATE("", "Thermostat", this); | ||||||
|  |  | ||||||
|   if (this->supports_two_points_) |   if (this->supports_two_points_) { | ||||||
|     ESP_LOGCONFIG(TAG, "  Minimum Set Point Differential: %.1f°C", this->set_point_minimum_differential_); |     ESP_LOGCONFIG(TAG, "  Minimum Set Point Differential: %.1f°C", this->set_point_minimum_differential_); | ||||||
|  |   } | ||||||
|   ESP_LOGCONFIG(TAG, "  Start-up Delay Enabled: %s", YESNO(this->use_startup_delay_)); |   ESP_LOGCONFIG(TAG, "  Start-up Delay Enabled: %s", YESNO(this->use_startup_delay_)); | ||||||
|   if (this->supports_cool_) { |   if (this->supports_cool_) { | ||||||
|     ESP_LOGCONFIG(TAG, "  Cooling Parameters:"); |     ESP_LOGCONFIG(TAG, "  Cooling Parameters:"); | ||||||
| @@ -1284,7 +1307,7 @@ void ThermostatClimate::dump_config() { | |||||||
|     const auto *preset_name = LOG_STR_ARG(climate::climate_preset_to_string(it.first)); |     const auto *preset_name = LOG_STR_ARG(climate::climate_preset_to_string(it.first)); | ||||||
|  |  | ||||||
|     ESP_LOGCONFIG(TAG, "    Supports %s: %s", preset_name, YESNO(true)); |     ESP_LOGCONFIG(TAG, "    Supports %s: %s", preset_name, YESNO(true)); | ||||||
|     this->dump_preset_config_(preset_name, it.second); |     this->dump_preset_config_(preset_name, it.second, it.first == this->default_preset_); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ESP_LOGCONFIG(TAG, "  Supported CUSTOM PRESETS: "); |   ESP_LOGCONFIG(TAG, "  Supported CUSTOM PRESETS: "); | ||||||
| @@ -1292,8 +1315,10 @@ void ThermostatClimate::dump_config() { | |||||||
|     const auto *preset_name = it.first.c_str(); |     const auto *preset_name = it.first.c_str(); | ||||||
|  |  | ||||||
|     ESP_LOGCONFIG(TAG, "    Supports %s: %s", preset_name, YESNO(true)); |     ESP_LOGCONFIG(TAG, "    Supports %s: %s", preset_name, YESNO(true)); | ||||||
|     this->dump_preset_config_(preset_name, it.second); |     this->dump_preset_config_(preset_name, it.second, it.first == this->default_custom_preset_); | ||||||
|   } |   } | ||||||
|  |   ESP_LOGCONFIG(TAG, "  On boot, restore from: %s", | ||||||
|  |                 this->on_boot_restore_from_ == thermostat::DEFAULT_PRESET ? "DEFAULT_PRESET" : "MEMORY"); | ||||||
| } | } | ||||||
|  |  | ||||||
| ThermostatClimateTargetTempConfig::ThermostatClimateTargetTempConfig() = default; | ThermostatClimateTargetTempConfig::ThermostatClimateTargetTempConfig() = default; | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ enum ThermostatClimateTimerIndex : size_t { | |||||||
|   TIMER_IDLE_ON = 9, |   TIMER_IDLE_ON = 9, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum OnBootRestoreFrom : size_t { MEMORY = 0, DEFAULT_PRESET = 1 }; | ||||||
| struct ThermostatClimateTimer { | struct ThermostatClimateTimer { | ||||||
|   const std::string name; |   const std::string name; | ||||||
|   bool active; |   bool active; | ||||||
| @@ -57,7 +58,9 @@ class ThermostatClimate : public climate::Climate, public Component { | |||||||
|   void setup() override; |   void setup() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|  |  | ||||||
|   void set_default_mode(climate::ClimateMode default_mode); |   void set_default_preset(const std::string &custom_preset); | ||||||
|  |   void set_default_preset(climate::ClimatePreset preset); | ||||||
|  |   void set_on_boot_restore_from(thermostat::OnBootRestoreFrom on_boot_restore_from); | ||||||
|   void set_set_point_minimum_differential(float differential); |   void set_set_point_minimum_differential(float differential); | ||||||
|   void set_cool_deadband(float deadband); |   void set_cool_deadband(float deadband); | ||||||
|   void set_cool_overrun(float overrun); |   void set_cool_overrun(float overrun); | ||||||
| @@ -225,7 +228,8 @@ class ThermostatClimate : public climate::Climate, public Component { | |||||||
|   bool supplemental_cooling_required_(); |   bool supplemental_cooling_required_(); | ||||||
|   bool supplemental_heating_required_(); |   bool supplemental_heating_required_(); | ||||||
|  |  | ||||||
|   void dump_preset_config_(const std::string &preset_name, const ThermostatClimateTargetTempConfig &config); |   void dump_preset_config_(const std::string &preset_name, const ThermostatClimateTargetTempConfig &config, | ||||||
|  |                            bool is_default_preset); | ||||||
|  |  | ||||||
|   /// The sensor used for getting the current temperature |   /// The sensor used for getting the current temperature | ||||||
|   sensor::Sensor *sensor_{nullptr}; |   sensor::Sensor *sensor_{nullptr}; | ||||||
| @@ -397,7 +401,6 @@ class ThermostatClimate : public climate::Climate, public Component { | |||||||
|   /// These are used to determine when a trigger/action needs to be called |   /// These are used to determine when a trigger/action needs to be called | ||||||
|   climate::ClimateAction supplemental_action_{climate::CLIMATE_ACTION_OFF}; |   climate::ClimateAction supplemental_action_{climate::CLIMATE_ACTION_OFF}; | ||||||
|   climate::ClimateFanMode prev_fan_mode_{climate::CLIMATE_FAN_ON}; |   climate::ClimateFanMode prev_fan_mode_{climate::CLIMATE_FAN_ON}; | ||||||
|   climate::ClimateMode default_mode_{climate::CLIMATE_MODE_OFF}; |  | ||||||
|   climate::ClimateMode prev_mode_{climate::CLIMATE_MODE_OFF}; |   climate::ClimateMode prev_mode_{climate::CLIMATE_MODE_OFF}; | ||||||
|   climate::ClimateSwingMode prev_swing_mode_{climate::CLIMATE_SWING_OFF}; |   climate::ClimateSwingMode prev_swing_mode_{climate::CLIMATE_SWING_OFF}; | ||||||
|  |  | ||||||
| @@ -441,6 +444,15 @@ class ThermostatClimate : public climate::Climate, public Component { | |||||||
|   std::map<climate::ClimatePreset, ThermostatClimateTargetTempConfig> preset_config_{}; |   std::map<climate::ClimatePreset, ThermostatClimateTargetTempConfig> preset_config_{}; | ||||||
|   /// The set of custom preset configurations this thermostat supports (eg. "My Custom Preset") |   /// The set of custom preset configurations this thermostat supports (eg. "My Custom Preset") | ||||||
|   std::map<std::string, ThermostatClimateTargetTempConfig> custom_preset_config_{}; |   std::map<std::string, ThermostatClimateTargetTempConfig> custom_preset_config_{}; | ||||||
|  |  | ||||||
|  |   /// Default standard preset to use on start up | ||||||
|  |   climate::ClimatePreset default_preset_{}; | ||||||
|  |   /// Default custom preset to use on start up | ||||||
|  |   std::string default_custom_preset_{}; | ||||||
|  |  | ||||||
|  |   /// If set to DEFAULT_PRESET then the default preset is always used. When MEMORY prior | ||||||
|  |   /// state will attempt to be restored if possible | ||||||
|  |   thermostat::OnBootRestoreFrom on_boot_restore_from_{thermostat::OnBootRestoreFrom::MEMORY}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace thermostat | }  // namespace thermostat | ||||||
|   | |||||||
| @@ -1061,8 +1061,13 @@ climate: | |||||||
|   - platform: thermostat |   - platform: thermostat | ||||||
|     name: Thermostat Climate |     name: Thermostat Climate | ||||||
|     sensor: ha_hello_world |     sensor: ha_hello_world | ||||||
|     default_target_temperature_low: 18°C |     preset: | ||||||
|     default_target_temperature_high: 24°C |     - name: Default Preset | ||||||
|  |       default_target_temperature_low: 18°C | ||||||
|  |       default_target_temperature_high: 24°C | ||||||
|  |     - name: Away | ||||||
|  |       default_target_temperature_low: 16°C | ||||||
|  |       default_target_temperature_high: 20°C | ||||||
|     idle_action: |     idle_action: | ||||||
|       - switch.turn_on: gpio_switch1 |       - switch.turn_on: gpio_switch1 | ||||||
|     cool_action: |     cool_action: | ||||||
| @@ -1137,9 +1142,6 @@ climate: | |||||||
|     fan_only_cooling: true |     fan_only_cooling: true | ||||||
|     fan_with_cooling: true |     fan_with_cooling: true | ||||||
|     fan_with_heating: true |     fan_with_heating: true | ||||||
|     away_config: |  | ||||||
|       default_target_temperature_low: 16°C |  | ||||||
|       default_target_temperature_high: 20°C |  | ||||||
|   - platform: pid |   - platform: pid | ||||||
|     id: pid_climate |     id: pid_climate | ||||||
|     name: PID Climate Controller |     name: PID Climate Controller | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user