1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-03 08:31:47 +00:00

Merge remote-tracking branch 'upstream/dev' into integration

# Conflicts:
#	esphome/components/bedjet/climate/bedjet_climate.cpp
#	esphome/components/climate/climate.cpp
#	esphome/components/climate/climate.h
#	esphome/components/demo/demo_climate.h
#	esphome/components/thermostat/thermostat_climate.cpp
This commit is contained in:
J. Nick Koston
2025-11-02 23:20:11 -06:00
11 changed files with 53 additions and 59 deletions

View File

@@ -100,7 +100,6 @@ enum BedjetCommand : uint8_t {
static const uint8_t BEDJET_FAN_SPEED_COUNT = 20;
static constexpr const char *const BEDJET_FAN_STEP_NAMES[BEDJET_FAN_SPEED_COUNT] = BEDJET_FAN_STEP_NAMES_;
static const std::string BEDJET_FAN_STEP_NAME_STRINGS[BEDJET_FAN_SPEED_COUNT] = BEDJET_FAN_STEP_NAMES_;
} // namespace bedjet
} // namespace esphome

View File

@@ -8,15 +8,15 @@ namespace bedjet {
using namespace esphome::climate;
static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) {
static const char *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) {
if (fan_step < BEDJET_FAN_SPEED_COUNT)
return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step];
return BEDJET_FAN_STEP_NAMES[fan_step];
return nullptr;
}
static uint8_t bedjet_fan_speed_to_step(const std::string &fan_step_percent) {
static uint8_t bedjet_fan_speed_to_step(const char *fan_step_percent) {
for (int i = 0; i < BEDJET_FAN_SPEED_COUNT; i++) {
if (fan_step_percent == BEDJET_FAN_STEP_NAME_STRINGS[i]) {
if (strcmp(BEDJET_FAN_STEP_NAMES[i], fan_step_percent) == 0) {
return i;
}
}
@@ -163,27 +163,27 @@ void BedJetClimate::control(const ClimateCall &call) {
ESP_LOGW(TAG, "Unsupported preset: %d", preset);
return;
}
} else if (call.get_custom_preset().has_value()) {
std::string preset = *call.get_custom_preset();
} else if (call.has_custom_preset()) {
const char *preset = call.get_custom_preset();
bool result;
if (preset == "M1") {
if (strcmp(preset, "M1") == 0) {
result = this->parent_->button_memory1();
} else if (preset == "M2") {
} else if (strcmp(preset, "M2") == 0) {
result = this->parent_->button_memory2();
} else if (preset == "M3") {
} else if (strcmp(preset, "M3") == 0) {
result = this->parent_->button_memory3();
} else if (preset == "LTD HT") {
} else if (strcmp(preset, "LTD HT") == 0) {
result = this->parent_->button_heat();
} else if (preset == "EXT HT") {
} else if (strcmp(preset, "EXT HT") == 0) {
result = this->parent_->button_ext_heat();
} else {
ESP_LOGW(TAG, "Unsupported preset: %s", preset.c_str());
ESP_LOGW(TAG, "Unsupported preset: %s", preset);
return;
}
if (result) {
this->set_custom_preset_(preset.c_str());
this->set_custom_preset_(preset);
}
}
@@ -207,15 +207,14 @@ void BedJetClimate::control(const ClimateCall &call) {
if (result) {
this->set_fan_mode_(fan_mode);
}
} else if (call.get_custom_fan_mode().has_value()) {
auto fan_mode = *call.get_custom_fan_mode();
} else if (call.has_custom_fan_mode()) {
const char *fan_mode = call.get_custom_fan_mode();
auto fan_index = bedjet_fan_speed_to_step(fan_mode);
if (fan_index <= 19) {
ESP_LOGV(TAG, "[%s] Converted fan mode %s to bedjet fan step %d", this->get_name().c_str(), fan_mode.c_str(),
fan_index);
ESP_LOGV(TAG, "[%s] Converted fan mode %s to bedjet fan step %d", this->get_name().c_str(), fan_mode, fan_index);
bool result = this->parent_->set_fan_index(fan_index);
if (result) {
this->set_custom_fan_mode_(fan_mode.c_str());
this->set_custom_fan_mode_(fan_mode);
}
}
}
@@ -241,7 +240,7 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) {
const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step);
if (fan_mode_name != nullptr) {
this->set_custom_fan_mode_(fan_mode_name->c_str());
this->set_custom_fan_mode_(fan_mode_name);
}
// TODO: Get biorhythm data to determine which preset (M1-3) is running, if any.

View File

@@ -292,14 +292,6 @@ const optional<ClimateFanMode> &ClimateCall::get_fan_mode() const { return this-
const optional<ClimateSwingMode> &ClimateCall::get_swing_mode() const { return this->swing_mode_; }
const optional<ClimatePreset> &ClimateCall::get_preset() const { return this->preset_; }
optional<std::string> ClimateCall::get_custom_fan_mode() const {
return this->custom_fan_mode_ != nullptr ? std::string(this->custom_fan_mode_) : optional<std::string>{};
}
optional<std::string> ClimateCall::get_custom_preset() const {
return this->custom_preset_ != nullptr ? std::string(this->custom_preset_) : optional<std::string>{};
}
ClimateCall &ClimateCall::set_target_temperature_high(optional<float> target_temperature_high) {
this->target_temperature_high_ = target_temperature_high;
return *this;

View File

@@ -107,8 +107,10 @@ class ClimateCall {
const optional<ClimateFanMode> &get_fan_mode() const;
const optional<ClimateSwingMode> &get_swing_mode() const;
const optional<ClimatePreset> &get_preset() const;
optional<std::string> get_custom_fan_mode() const;
optional<std::string> get_custom_preset() const;
const char *get_custom_fan_mode() const { return this->custom_fan_mode_; }
const char *get_custom_preset() const { return this->custom_preset_; }
bool has_custom_fan_mode() const { return this->custom_fan_mode_ != nullptr; }
bool has_custom_preset() const { return this->custom_preset_ != nullptr; }
protected:
void validate_();
@@ -122,6 +124,8 @@ class ClimateCall {
optional<ClimateFanMode> fan_mode_;
optional<ClimateSwingMode> swing_mode_;
optional<ClimatePreset> preset_;
private:
const char *custom_fan_mode_{nullptr};
const char *custom_preset_{nullptr};
};

View File

@@ -63,14 +63,14 @@ class DemoClimate : public climate::Climate, public Component {
if (call.get_swing_mode().has_value()) {
this->swing_mode = *call.get_swing_mode();
}
if (call.get_custom_fan_mode().has_value()) {
this->set_custom_fan_mode_(call.get_custom_fan_mode()->c_str());
if (call.has_custom_fan_mode()) {
this->set_custom_fan_mode_(call.get_custom_fan_mode());
}
if (call.get_preset().has_value()) {
this->set_preset_(*call.get_preset());
}
if (call.get_custom_preset().has_value()) {
this->set_custom_preset_(call.get_custom_preset()->c_str());
if (call.has_custom_preset()) {
this->set_custom_preset_(call.get_custom_preset());
}
this->publish_state();
}

View File

@@ -117,8 +117,8 @@ const char *Converters::to_custom_climate_fan_mode(MideaFanMode mode) {
}
}
MideaFanMode Converters::to_midea_fan_mode(const std::string &mode) {
if (mode == Constants::SILENT)
MideaFanMode Converters::to_midea_fan_mode(const char *mode) {
if (strcmp(mode, Constants::SILENT) == 0)
return MideaFanMode::FAN_SILENT;
return MideaFanMode::FAN_TURBO;
}
@@ -153,7 +153,7 @@ bool Converters::is_custom_midea_preset(MideaPreset preset) { return preset == M
const char *Converters::to_custom_climate_preset(MideaPreset preset) { return Constants::FREEZE_PROTECTION; }
MideaPreset Converters::to_midea_preset(const std::string &preset) { return MideaPreset::PRESET_FREEZE_PROTECTION; }
MideaPreset Converters::to_midea_preset(const char *preset) { return MideaPreset::PRESET_FREEZE_PROTECTION; }
void Converters::to_climate_traits(ClimateTraits &traits, const dudanov::midea::ac::Capabilities &capabilities) {
if (capabilities.supportAutoMode())

View File

@@ -32,12 +32,12 @@ class Converters {
static MideaSwingMode to_midea_swing_mode(ClimateSwingMode mode);
static ClimateSwingMode to_climate_swing_mode(MideaSwingMode mode);
static MideaPreset to_midea_preset(ClimatePreset preset);
static MideaPreset to_midea_preset(const std::string &preset);
static MideaPreset to_midea_preset(const char *preset);
static bool is_custom_midea_preset(MideaPreset preset);
static ClimatePreset to_climate_preset(MideaPreset preset);
static const char *to_custom_climate_preset(MideaPreset preset);
static MideaFanMode to_midea_fan_mode(ClimateFanMode fan_mode);
static MideaFanMode to_midea_fan_mode(const std::string &fan_mode);
static MideaFanMode to_midea_fan_mode(const char *fan_mode);
static bool is_custom_midea_fan_mode(MideaFanMode fan_mode);
static ClimateFanMode to_climate_fan_mode(MideaFanMode fan_mode);
static const char *to_custom_climate_fan_mode(MideaFanMode fan_mode);

View File

@@ -64,13 +64,13 @@ void AirConditioner::control(const ClimateCall &call) {
ctrl.mode = Converters::to_midea_mode(call.get_mode().value());
if (call.get_preset().has_value()) {
ctrl.preset = Converters::to_midea_preset(call.get_preset().value());
} else if (call.get_custom_preset().has_value()) {
ctrl.preset = Converters::to_midea_preset(call.get_custom_preset().value());
} else if (call.has_custom_preset()) {
ctrl.preset = Converters::to_midea_preset(call.get_custom_preset());
}
if (call.get_fan_mode().has_value()) {
ctrl.fanMode = Converters::to_midea_fan_mode(call.get_fan_mode().value());
} else if (call.get_custom_fan_mode().has_value()) {
ctrl.fanMode = Converters::to_midea_fan_mode(call.get_custom_fan_mode().value());
} else if (call.has_custom_fan_mode()) {
ctrl.fanMode = Converters::to_midea_fan_mode(call.get_custom_fan_mode());
}
this->base_.control(ctrl);
}

View File

@@ -54,7 +54,7 @@ void ThermostatClimate::setup() {
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_);
this->change_custom_preset_(this->default_custom_preset_.c_str());
}
}
@@ -218,13 +218,13 @@ void ThermostatClimate::control(const climate::ClimateCall &call) {
this->preset = call.get_preset().value();
}
}
if (call.get_custom_preset().has_value()) {
if (call.has_custom_preset()) {
// setup_complete_ blocks modifying/resetting the temps immediately after boot
if (this->setup_complete_) {
this->change_custom_preset_(call.get_custom_preset().value());
this->change_custom_preset_(call.get_custom_preset());
} else {
// Use the base class method which handles pointer lookup internally
this->set_custom_preset_(call.get_custom_preset().value().c_str());
this->set_custom_preset_(call.get_custom_preset());
}
}
@@ -1177,31 +1177,31 @@ void ThermostatClimate::change_preset_(climate::ClimatePreset preset) {
}
}
void ThermostatClimate::change_custom_preset_(const std::string &custom_preset) {
void ThermostatClimate::change_custom_preset_(const char *custom_preset) {
auto config = this->custom_preset_config_.find(custom_preset);
if (config != this->custom_preset_config_.end()) {
ESP_LOGV(TAG, "Custom preset %s requested", custom_preset.c_str());
ESP_LOGV(TAG, "Custom preset %s requested", custom_preset);
if (this->change_preset_internal_(config->second) || !this->has_custom_preset() ||
strcmp(this->get_custom_preset(), custom_preset.c_str()) != 0) {
strcmp(this->get_custom_preset(), custom_preset) != 0) {
// Fire any preset changed trigger if defined
Trigger<> *trig = this->preset_change_trigger_;
// Use the base class method which handles pointer lookup and preset reset internally
this->set_custom_preset_(custom_preset.c_str());
this->set_custom_preset_(custom_preset);
if (trig != nullptr) {
trig->trigger();
}
this->refresh();
ESP_LOGI(TAG, "Custom preset %s applied", custom_preset.c_str());
ESP_LOGI(TAG, "Custom preset %s applied", custom_preset);
} else {
ESP_LOGI(TAG, "No changes required to apply custom preset %s", custom_preset.c_str());
ESP_LOGI(TAG, "No changes required to apply custom preset %s", custom_preset);
// Note: set_custom_preset_() above handles preset.reset() and custom_preset_ assignment internally.
// The old code had these lines here unconditionally, which was a bug (double assignment, state modification
// even when no changes were needed). Now properly handled by the protected setter with mutual exclusion.
}
// Note: set_custom_preset_() above handles preset.reset() and custom_preset_ assignment internally.
// The old code had these lines here unconditionally, which was a bug (double assignment, state modification
// even when no changes were needed). Now properly handled by the protected setter with mutual exclusion.
} else {
ESP_LOGW(TAG, "Custom preset %s not configured; ignoring", custom_preset.c_str());
ESP_LOGW(TAG, "Custom preset %s not configured; ignoring", custom_preset);
}
}

View File

@@ -199,7 +199,7 @@ class ThermostatClimate : public climate::Climate, public Component {
/// Change to a provided preset setting; will reset temperature, mode, fan, and swing modes accordingly
void change_preset_(climate::ClimatePreset preset);
/// Change to a provided custom preset setting; will reset temperature, mode, fan, and swing modes accordingly
void change_custom_preset_(const std::string &custom_preset);
void change_custom_preset_(const char *custom_preset);
/// Applies the temperature, mode, fan, and swing modes of the provided config.
/// This is agnostic of custom vs built in preset

View File

@@ -12,7 +12,7 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
esptool==5.1.0
click==8.1.7
esphome-dashboard==20251013.0
aioesphomeapi==42.5.0
aioesphomeapi==42.6.0
zeroconf==0.148.0
puremagic==1.30
ruamel.yaml==0.18.16 # dashboard_import