Merge pull request #196 from GrKoR/dev-esphome2026-1-0-fix

ESPHome 2026.1.0 Breaking Changes & Code Optimization
This commit is contained in:
GK
2026-01-22 01:47:52 -08:00
committed by GitHub
4 changed files with 64 additions and 326 deletions

View File

@@ -36,7 +36,8 @@ The best way to report about your test results is writing a message in the [tele
For correct component operation, you need hardware and firmware. The hardware description is located [in a separate file](docs/HARDWARE-EN.md). For correct component operation, you need hardware and firmware. The hardware description is located [in a separate file](docs/HARDWARE-EN.md).
### Firmware: Integration aux_ac to your configuration ### ### Firmware: Integration aux_ac to your configuration ###
You need [ESPHome](https://esphome.io) v.2025.2.0 or above. You can try esphome before 2025.2.0 but I can't guarantee error-free compilation of the examples. You need [ESPHome](https://esphome.io) v.2026.1.0 or above.
To compile it with earlier versions of ESPHome, use the component [v.0.3.2 or older](https://github.com/GrKoR/esphome_aux_ac_component/tags).
## Installing ## ## Installing ##
1. Declare external component. Read [the manual](https://esphome.io/components/external_components.html?highlight=external) for details. 1. Declare external component. Read [the manual](https://esphome.io/components/external_components.html?highlight=external) for details.

View File

@@ -43,7 +43,8 @@ AUX - это один из нескольких OEM-производителей
Для работы с кондиционером понадобится "железо" и прошивка. Описание электроники вынесено [в отдельный файл](docs/HARDWARE.md). Для работы с кондиционером понадобится "железо" и прошивка. Описание электроники вынесено [в отдельный файл](docs/HARDWARE.md).
### Прошивка: интеграция aux_ac в вашу конфигурацию ESPHome ### ### Прошивка: интеграция aux_ac в вашу конфигурацию ESPHome ###
Для использования требуется [ESPHome](https://esphome.io) версией не ниже 2025.2.0. Работа с более ранними версиями возможна, но не гарантируется.<br /> Для использования требуется [ESPHome](https://esphome.io) версией не ниже 2026.1.0.
Для компиляции с ESPHome более ранних версий используйте компонент [v.0.3.2 или младше](https://github.com/GrKoR/esphome_aux_ac_component/tags).
## Установка ## ## Установка ##
1. Подключите компонент. 1. Подключите компонент.

View File

@@ -44,11 +44,9 @@ namespace esphome
using climate::ClimatePreset; using climate::ClimatePreset;
using climate::ClimateSwingMode; using climate::ClimateSwingMode;
using climate::ClimateTraits; using climate::ClimateTraits;
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
using climate::ClimateModeMask; using climate::ClimateModeMask;
using climate::ClimateSwingModeMask; using climate::ClimateSwingModeMask;
using climate::ClimatePresetMask; using climate::ClimatePresetMask;
#endif
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
//**************************************************** Packet logger configuration ******************************************************************* //**************************************************** Packet logger configuration *******************************************************************
@@ -94,57 +92,37 @@ namespace esphome
class Constants class Constants
{ {
public: public:
static const std::string AC_FIRMWARE_VERSION; // AUX_AC_FIRMWARE_VERSION is defined by the ESPHome code generator at compile time
static constexpr const char* AC_FIRMWARE_VERSION = AUX_AC_FIRMWARE_VERSION;
static const std::string MUTE; // custom fan modes
static const std::string TURBO; static constexpr const char* MUTE = "mute";
static const std::string CLEAN; static constexpr const char* TURBO = "turbo";
static const std::string HEALTH;
static const std::string ANTIFUNGUS; // custom presets
static constexpr const char* CLEAN = "Clean";
static constexpr const char* HEALTH = "Health";
static constexpr const char* ANTIFUNGUS = "Antifungus";
/// минимальная и максимальная температура в градусах Цельсия, ограничения самого кондиционера /// минимальная и максимальная температура в градусах Цельсия, ограничения самого кондиционера
static const float AC_MIN_TEMPERATURE; static constexpr const float AC_MIN_TEMPERATURE = 16.0;
static const float AC_MAX_TEMPERATURE; static constexpr const float AC_MAX_TEMPERATURE = 32.0;
/// шаг изменения целевой температуры, градусы Цельсия /// Target temperature step, Celsius degrees
static const float AC_TEMPERATURE_STEP; static constexpr const float AC_TEMPERATURE_STEP = 0.5;
/// минимальное и максимальное значение мощности инвертора при установке ограничений /// Minimal and maximal values of invertor power
static const uint8_t AC_MIN_INVERTER_POWER_LIMIT; // AUX_AC_MIN_INVERTER_POWER_LIMIT and AUX_AC_MAX_INVERTER_POWER_LIMIT are defined by the ESPHome code generator at compile time
static const uint8_t AC_MAX_INVERTER_POWER_LIMIT; static constexpr const uint8_t AC_MIN_INVERTER_POWER_LIMIT = AUX_AC_MIN_INVERTER_POWER_LIMIT;
static constexpr const uint8_t AC_MAX_INVERTER_POWER_LIMIT = AUX_AC_MAX_INVERTER_POWER_LIMIT;
// периодичность опроса кондиционера на предмет изменения состояния // периодичность опроса кондиционера на предмет изменения состояния
// изменение параметров с пульта не сообщается в UART, поэтому надо запрашивать состояние, чтобы быть в курсе // изменение параметров с пульта не сообщается в UART, поэтому надо запрашивать состояние, чтобы быть в курсе
// значение в миллисекундах // значение в миллисекундах
static const uint32_t AC_STATES_REQUEST_INTERVAL; static constexpr const uint32_t AC_STATES_REQUEST_INTERVAL = 7000;
// границы допустимого диапазона таймаута загрузки пакета // границы допустимого диапазона таймаута загрузки пакета
// таймаут загрузки - через такое количиство миллисекунд конечный автомат перейдет из // таймаут загрузки - через такое количиство миллисекунд конечный автомат перейдет из
// состояния ACSM_RECEIVING_PACKET в ACSM_IDLE, если пакет не будет загружен // состояния ACSM_RECEIVING_PACKET в ACSM_IDLE, если пакет не будет загружен
static const uint32_t AC_PACKET_TIMEOUT_MAX;
static const uint32_t AC_PACKET_TIMEOUT_MIN;
};
// AUX_AC_FIRMWARE_VERSION will be defined by the ESPHome code generator at compile time
const std::string Constants::AC_FIRMWARE_VERSION = AUX_AC_FIRMWARE_VERSION;
// custom fan modes
const std::string Constants::MUTE = "mute";
const std::string Constants::TURBO = "turbo";
// custom presets
const std::string Constants::CLEAN = "Clean";
const std::string Constants::HEALTH = "Health";
const std::string Constants::ANTIFUNGUS = "Antifungus";
// params
const float Constants::AC_MIN_TEMPERATURE = 16.0;
const float Constants::AC_MAX_TEMPERATURE = 32.0;
const float Constants::AC_TEMPERATURE_STEP = 0.5;
// AUX_AC_MIN_INVERTER_POWER_LIMIT and AUX_AC_MAX_INVERTER_POWER_LIMIT will be defined by the ESPHome code generator at compile time
const uint8_t Constants::AC_MIN_INVERTER_POWER_LIMIT = AUX_AC_MIN_INVERTER_POWER_LIMIT;
const uint8_t Constants::AC_MAX_INVERTER_POWER_LIMIT = AUX_AC_MAX_INVERTER_POWER_LIMIT;
const uint32_t Constants::AC_STATES_REQUEST_INTERVAL = 7000;
// таймаут загрузки пакета
// По расчетам выходит: // По расчетам выходит:
// - получение и обработка посимвольно не должна длиться дольше 600 мсек. // - получение и обработка посимвольно не должна длиться дольше 600 мсек.
// - получение и обработка пакетов целиком не должна длиться дольше 150 мсек. // - получение и обработка пакетов целиком не должна длиться дольше 150 мсек.
@@ -154,9 +132,10 @@ namespace esphome
// команды будут теряться. От такой коллизии мы не защищены в любом случае. Но чем меньше таймаут, // команды будут теряться. От такой коллизии мы не защищены в любом случае. Но чем меньше таймаут,
// тем меньше шансов на коллизию. // тем меньше шансов на коллизию.
// Из этих соображений выбраны границы диапазона (_MIN и _MAX значения). // Из этих соображений выбраны границы диапазона (_MIN и _MAX значения).
// AUX_AC_PACKET_TIMEOUT_MAX and AUX_AC_PACKET_TIMEOUT_MIN will be defined by the ESPHome code generator at compile time // AUX_AC_PACKET_TIMEOUT_MAX and AUX_AC_PACKET_TIMEOUT_MIN are defined by the ESPHome code generator at compile time
const uint32_t Constants::AC_PACKET_TIMEOUT_MAX = AUX_AC_PACKET_TIMEOUT_MAX; static constexpr const uint32_t AC_PACKET_TIMEOUT_MAX = AUX_AC_PACKET_TIMEOUT_MAX;
const uint32_t Constants::AC_PACKET_TIMEOUT_MIN = AUX_AC_PACKET_TIMEOUT_MIN; static constexpr const uint32_t AC_PACKET_TIMEOUT_MIN = AUX_AC_PACKET_TIMEOUT_MIN;
};
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
//********************************************************* ОСНОВНЫЕ СТРУКТУРЫ *********************************************************************** //********************************************************* ОСНОВНЫЕ СТРУКТУРЫ ***********************************************************************
@@ -858,19 +837,11 @@ namespace esphome
// как "в простое" (IDLE) // как "в простое" (IDLE)
bool _is_inverter = false; bool _is_inverter = false;
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
ClimateModeMask _supported_modes{}; ClimateModeMask _supported_modes{};
ClimateSwingModeMask _supported_swing_modes{}; ClimateSwingModeMask _supported_swing_modes{};
ClimatePresetMask _supported_presets{}; ClimatePresetMask _supported_presets{};
std::vector<const char *> _supported_custom_fan_modes{}; std::vector<const char *> _supported_custom_fan_modes{};
std::vector<const char *> _supported_custom_presets{}; std::vector<const char *> _supported_custom_presets{};
#else
std::set<ClimateMode> _supported_modes{};
std::set<ClimateSwingMode> _supported_swing_modes{};
std::set<ClimatePreset> _supported_presets{};
std::set<std::string> _supported_custom_presets{};
std::set<std::string> _supported_custom_fan_modes{};
#endif
// The capabilities of the climate device // The capabilities of the climate device
// Шаблон параметров отображения виджета // Шаблон параметров отображения виджета
@@ -2404,13 +2375,8 @@ namespace esphome
// первоначальная инициализация // первоначальная инициализация
this->preset = climate::CLIMATE_PRESET_NONE; this->preset = climate::CLIMATE_PRESET_NONE;
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->clear_custom_preset_(); this->clear_custom_preset_();
this->clear_custom_fan_mode_(); this->clear_custom_fan_mode_();
#else
this->custom_preset = (std::string) "";
this->custom_fan_mode = (std::string) "";
#endif
this->mode = climate::CLIMATE_MODE_OFF; this->mode = climate::CLIMATE_MODE_OFF;
this->action = climate::CLIMATE_ACTION_IDLE; this->action = climate::CLIMATE_ACTION_IDLE;
this->fan_mode = climate::CLIMATE_FAN_LOW; this->fan_mode = climate::CLIMATE_FAN_LOW;
@@ -2653,24 +2619,13 @@ namespace esphome
switch (_current_ac_state.fanTurbo) switch (_current_ac_state.fanTurbo)
{ {
case AC_FANTURBO_ON: case AC_FANTURBO_ON:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) this->set_custom_fan_mode_(Constants::TURBO);
this->set_custom_fan_mode_(Constants::TURBO.c_str());
#else
this->custom_fan_mode = Constants::TURBO;
#endif
break; break;
case AC_FANTURBO_OFF: case AC_FANTURBO_OFF:
default: default:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) if (this->has_custom_fan_mode() && (this->get_custom_fan_mode() == Constants::TURBO))
if (this->has_custom_fan_mode()) {
if (strcmp(this->get_custom_fan_mode(), Constants::TURBO.c_str()) == 0)
this->clear_custom_fan_mode_(); this->clear_custom_fan_mode_();
}
#else
if (this->custom_fan_mode == Constants::TURBO)
this->custom_fan_mode = (std::string) "";
#endif
break; break;
} }
@@ -2682,24 +2637,13 @@ namespace esphome
switch (_current_ac_state.fanMute) switch (_current_ac_state.fanMute)
{ {
case AC_FANMUTE_ON: case AC_FANMUTE_ON:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) this->set_custom_fan_mode_(Constants::MUTE);
this->set_custom_fan_mode_(Constants::MUTE.c_str());
#else
this->custom_fan_mode = Constants::MUTE;
#endif
break; break;
case AC_FANMUTE_OFF: case AC_FANMUTE_OFF:
default: default:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) if (this->has_custom_fan_mode() && (this->get_custom_fan_mode() == Constants::MUTE))
if (this->has_custom_fan_mode()) {
if (strcmp(this->get_custom_fan_mode(), Constants::MUTE.c_str()) == 0)
this->clear_custom_fan_mode_(); this->clear_custom_fan_mode_();
}
#else
if (this->custom_fan_mode == Constants::MUTE)
this->custom_fan_mode = (std::string) "";
#endif
break; break;
} }
@@ -2711,25 +2655,14 @@ namespace esphome
if (_current_ac_state.health == AC_HEALTH_ON && if (_current_ac_state.health == AC_HEALTH_ON &&
_current_ac_state.power == AC_POWER_ON) _current_ac_state.power == AC_POWER_ON)
{ {
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) this->set_custom_preset_(Constants::HEALTH);
this->set_custom_preset_(Constants::HEALTH.c_str());
#else
this->custom_preset = Constants::HEALTH;
#endif
} }
// AC_HEALTH_OFF // AC_HEALTH_OFF
// только в том случае, если до этого пресет был установлен // только в том случае, если до этого пресет был установлен
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) else if (this->has_custom_preset() && (this->get_custom_preset() == Constants::HEALTH))
else if (this->has_custom_preset() && strcmp(this->get_custom_preset(), Constants::HEALTH.c_str()) == 0)
{ {
this->clear_custom_preset_(); this->clear_custom_preset_();
} }
#else
else if (this->custom_preset == Constants::HEALTH)
{
this->custom_preset = (std::string) "";
}
#endif
_debugMsg(F("Climate HEALTH preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.health); _debugMsg(F("Climate HEALTH preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.health);
@@ -2757,25 +2690,14 @@ namespace esphome
if (_current_ac_state.clean == AC_CLEAN_ON && if (_current_ac_state.clean == AC_CLEAN_ON &&
_current_ac_state.power == AC_POWER_OFF) _current_ac_state.power == AC_POWER_OFF)
{ {
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) this->set_custom_preset_(Constants::CLEAN);
this->set_custom_preset_(Constants::CLEAN.c_str());
#else
this->custom_preset = Constants::CLEAN;
#endif
} }
// AC_CLEAN_OFF // AC_CLEAN_OFF
// только в том случае, если до этого пресет был установлен // только в том случае, если до этого пресет был установлен
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) else if (this->has_custom_preset() && (this->get_custom_preset() == Constants::CLEAN))
else if (this->has_custom_preset() && strcmp(this->get_custom_preset(), Constants::CLEAN.c_str()) == 0)
{ {
this->clear_custom_preset_(); this->clear_custom_preset_();
} }
#else
else if (this->custom_preset == Constants::CLEAN)
{
this->custom_preset = (std::string) "";
}
#endif
_debugMsg(F("Climate CLEAN preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.clean); _debugMsg(F("Climate CLEAN preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.clean);
@@ -2798,26 +2720,14 @@ namespace esphome
switch (_current_ac_state.mildew) switch (_current_ac_state.mildew)
{ {
case AC_MILDEW_ON: case AC_MILDEW_ON:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) this->set_custom_preset_(Constants::ANTIFUNGUS);
this->set_custom_preset_(Constants::ANTIFUNGUS.c_str());
#else
this->custom_preset = Constants::ANTIFUNGUS;
#endif
break; break;
case AC_MILDEW_OFF: case AC_MILDEW_OFF:
default: default:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0) if (this->has_custom_preset() && (this->get_custom_preset() == Constants::ANTIFUNGUS))
if (this->has_custom_preset() && strcmp(this->get_custom_preset(), Constants::ANTIFUNGUS.c_str()) == 0)
{
this->clear_custom_preset_(); this->clear_custom_preset_();
} }
#else
if (this->custom_preset == Constants::ANTIFUNGUS)
this->custom_preset = (std::string) "";
break;
#endif
}
_debugMsg(F("Climate ANTIFUNGUS preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.mildew); _debugMsg(F("Climate ANTIFUNGUS preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.mildew);
@@ -2902,17 +2812,10 @@ namespace esphome
{ {
state_str += "SLEEP"; state_str += "SLEEP";
} }
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (this->has_custom_preset()) else if (this->has_custom_preset())
{ {
state_str += this->get_custom_preset(); state_str += this->get_custom_preset();
} }
#else
else if (this->custom_preset.has_value() && this->custom_preset.value().length() > 0)
{
state_str += this->custom_preset.value().c_str();
}
#endif
else else
{ {
state_str += "NONE"; state_str += "NONE";
@@ -2931,7 +2834,7 @@ namespace esphome
void dump_config() void dump_config()
{ {
ESP_LOGCONFIG(TAG, "AUX HVAC:"); ESP_LOGCONFIG(TAG, "AUX HVAC:");
ESP_LOGCONFIG(TAG, " [x] Firmware version: %s", Constants::AC_FIRMWARE_VERSION.c_str()); ESP_LOGCONFIG(TAG, " [x] Firmware version: %s", Constants::AC_FIRMWARE_VERSION);
ESP_LOGCONFIG(TAG, " [x] Period: %" PRIu32 "ms", this->get_period()); ESP_LOGCONFIG(TAG, " [x] Period: %" PRIu32 "ms", this->get_period());
ESP_LOGCONFIG(TAG, " [x] Show action: %s", TRUEFALSE(this->get_show_action())); ESP_LOGCONFIG(TAG, " [x] Show action: %s", TRUEFALSE(this->get_show_action()));
ESP_LOGCONFIG(TAG, " [x] Display inverted: %s", TRUEFALSE(this->get_display_inverted())); ESP_LOGCONFIG(TAG, " [x] Display inverted: %s", TRUEFALSE(this->get_display_inverted()));
@@ -3102,21 +3005,19 @@ namespace esphome
break; break;
} }
} }
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (call.has_custom_fan_mode()) else if (call.has_custom_fan_mode())
{ {
const char *customfanmode = call.get_custom_fan_mode(); auto custom_fan_mode = call.get_custom_fan_mode();
if (custom_fan_mode == Constants::TURBO)
if (strcmp(customfanmode, Constants::TURBO.c_str()) == 0)
{ {
// TURBO fan mode is suitable in COOL and HEAT modes. // TURBO fan mode is suitable in COOL and HEAT modes.
// Other modes don't accept TURBO fan mode. // Other modes don't accept TURBO fan mode.
hasCommand = true; hasCommand = true;
cmd.fanTurbo = AC_FANTURBO_ON; cmd.fanTurbo = AC_FANTURBO_ON;
cmd.fanMute = AC_FANMUTE_OFF; cmd.fanMute = AC_FANMUTE_OFF;
this->set_custom_fan_mode_(customfanmode); this->set_custom_fan_mode_(custom_fan_mode);
} }
else if (strcmp(customfanmode, Constants::MUTE.c_str()) == 0) else if (custom_fan_mode == Constants::MUTE)
{ {
// MUTE fan mode is suitable in FAN mode only for Rovex air conditioner. // MUTE fan mode is suitable in FAN mode only for Rovex air conditioner.
// In COOL mode AC receives command without any changes. // In COOL mode AC receives command without any changes.
@@ -3124,52 +3025,9 @@ namespace esphome
hasCommand = true; hasCommand = true;
cmd.fanMute = AC_FANMUTE_ON; cmd.fanMute = AC_FANMUTE_ON;
cmd.fanTurbo = AC_FANTURBO_OFF; cmd.fanTurbo = AC_FANTURBO_OFF;
this->set_custom_fan_mode_(customfanmode); this->set_custom_fan_mode_(custom_fan_mode);
} }
} }
#else
else if (call.get_custom_fan_mode().has_value())
{
std::string customfanmode = *call.get_custom_fan_mode();
if (customfanmode == Constants::TURBO)
{
// TURBO fan mode is suitable in COOL and HEAT modes.
// Other modes don't accept TURBO fan mode.
/*
if ( cmd.mode == AC_MODE_COOL
or cmd.mode == AC_MODE_HEAT
or _current_ac_state.mode == AC_MODE_COOL
or _current_ac_state.mode == AC_MODE_HEAT) {
*/
hasCommand = true;
cmd.fanTurbo = AC_FANTURBO_ON;
cmd.fanMute = AC_FANMUTE_OFF; // зависимость от fanturbo
this->custom_fan_mode = customfanmode;
/*
} else {
_debugMsg(F("TURBO fan mode is suitable in COOL and HEAT modes only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
}
*/
}
else if (customfanmode == Constants::MUTE)
{
// MUTE fan mode is suitable in FAN mode only for Rovex air conditioner.
// In COOL mode AC receives command without any changes.
// May be other AUX-based air conditioners do the same.
// if ( cmd.mode == AC_MODE_FAN
// or _current_ac_state.mode == AC_MODE_FAN) {
hasCommand = true;
cmd.fanMute = AC_FANMUTE_ON;
cmd.fanTurbo = AC_FANTURBO_OFF; // зависимость от fanmute
this->custom_fan_mode = customfanmode;
//} else {
// _debugMsg(F("MUTE fan mode is suitable in FAN mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
//}
}
}
#endif
// Пользователь выбрал пресет // Пользователь выбрал пресет
if (call.get_preset().has_value()) if (call.get_preset().has_value())
@@ -3220,28 +3078,25 @@ namespace esphome
break; break;
} }
} }
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (call.has_custom_preset()) else if (call.has_custom_preset())
{ {
const char *custom_preset = call.get_custom_preset(); auto custom_preset = call.get_custom_preset();
if (custom_preset == Constants::CLEAN)
if (strcmp(custom_preset, Constants::CLEAN.c_str()) == 0)
{ {
// режим очистки кондиционера, включается (или должен включаться) при AC_POWER_OFF // режим очистки кондиционера, включается (или должен включаться) при AC_POWER_OFF
// TODO: надо отдебажить выключение этого режима
if (cmd.power == AC_POWER_OFF or _current_ac_state.power == AC_POWER_OFF) if (cmd.power == AC_POWER_OFF or _current_ac_state.power == AC_POWER_OFF)
{ {
hasCommand = true; hasCommand = true;
cmd.clean = AC_CLEAN_ON; cmd.clean = AC_CLEAN_ON;
cmd.mildew = AC_MILDEW_OFF; cmd.mildew = AC_MILDEW_OFF;
this->set_custom_preset_(custom_preset); this->set_custom_preset_(Constants::CLEAN);
} }
else else
{ {
_debugMsg(F("CLEAN preset is suitable in POWER_OFF mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__); _debugMsg(F("CLEAN preset is suitable in POWER_OFF mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
} }
} }
else if (strcmp(custom_preset, Constants::HEALTH.c_str()) == 0) else if (custom_preset == Constants::HEALTH)
{ {
if (cmd.power == AC_POWER_ON || if (cmd.power == AC_POWER_ON ||
_current_ac_state.power == AC_POWER_ON) _current_ac_state.power == AC_POWER_ON)
@@ -3266,81 +3121,7 @@ namespace esphome
{ {
cmd.fanSpeed = AC_FANSPEED_MEDIUM; // зависимость от health cmd.fanSpeed = AC_FANSPEED_MEDIUM; // зависимость от health
} }
this->set_custom_preset_(custom_preset); this->set_custom_preset_(Constants::HEALTH);
}
else
{
_debugMsg(F("HEALTH preset is suitable in POWER_ON mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
}
}
else if (strcmp(custom_preset, Constants::ANTIFUNGUS.c_str()) == 0)
{
// включение-выключение функции "Антиплесень".
// По факту: после выключения сплита он оставляет минут на 5 открытые жалюзи и глушит вентилятор.
// Уличный блок при этом гудит и тарахтит. Возможно, прогревается теплообменник для высыхания.
// Через некоторое время внешний блок замолкает и сплит закрывает жалюзи.
// Brokly:
// включение-выключение функции "Антиплесень".
// у меня пульт отправляет 5 посылок и на включение и на выключение, но реагирует на эту кнопку
// только в режиме POWER_OFF
// TODO: надо уточнить, в каких режимах штатно включается этот режим у кондиционера
cmd.mildew = AC_MILDEW_ON;
cmd.clean = AC_CLEAN_OFF; // для логики пресетов
hasCommand = true;
this->set_custom_preset_(custom_preset);
}
}
#else
else if (call.get_custom_preset().has_value())
{
std::string custom_preset = *call.get_custom_preset();
if (custom_preset == Constants::CLEAN)
{
// режим очистки кондиционера, включается (или должен включаться) при AC_POWER_OFF
// TODO: надо отдебажить выключение этого режима
if (cmd.power == AC_POWER_OFF or _current_ac_state.power == AC_POWER_OFF)
{
hasCommand = true;
cmd.clean = AC_CLEAN_ON;
cmd.mildew = AC_MILDEW_OFF; // для логики пресетов
this->custom_preset = custom_preset;
}
else
{
_debugMsg(F("CLEAN preset is suitable in POWER_OFF mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
}
}
else if (custom_preset == Constants::HEALTH)
{
if (cmd.power == AC_POWER_ON ||
_current_ac_state.power == AC_POWER_ON)
{
hasCommand = true;
cmd.health = AC_HEALTH_ON;
// cmd.health_status = AC_HEALTH_STATUS_ON; // GK: статус кондей сам поднимает
cmd.fanTurbo = AC_FANTURBO_OFF; // зависимость от health
cmd.fanMute = AC_FANMUTE_OFF; // зависимость от health
cmd.sleep = AC_SLEEP_OFF; // для логики пресетов
if (cmd.mode == AC_MODE_COOL ||
cmd.mode == AC_MODE_HEAT ||
cmd.mode == AC_MODE_AUTO ||
_current_ac_state.mode == AC_MODE_COOL ||
_current_ac_state.mode == AC_MODE_HEAT ||
_current_ac_state.mode == AC_MODE_AUTO)
{
cmd.fanSpeed = AC_FANSPEED_AUTO; // зависимость от health
}
else if (cmd.mode == AC_MODE_FAN ||
_current_ac_state.mode == AC_MODE_FAN)
{
cmd.fanSpeed = AC_FANSPEED_MEDIUM; // зависимость от health
}
this->custom_preset = custom_preset;
} }
else else
{ {
@@ -3359,15 +3140,13 @@ namespace esphome
// у меня пульт отправляет 5 посылок и на включение и на выключение, но реагирует на эту кнопку // у меня пульт отправляет 5 посылок и на включение и на выключение, но реагирует на эту кнопку
// только в режиме POWER_OFF // только в режиме POWER_OFF
// TODO: надо уточнить, в каких режимах штатно включается этот режим у кондиционера
cmd.mildew = AC_MILDEW_ON; cmd.mildew = AC_MILDEW_ON;
cmd.clean = AC_CLEAN_OFF; // для логики пресетов cmd.clean = AC_CLEAN_OFF; // для логики пресетов
hasCommand = true; hasCommand = true;
this->custom_preset = custom_preset; this->set_custom_preset_(Constants::ANTIFUNGUS);
} }
} }
#endif
// User requested swing_mode change // User requested swing_mode change
if (call.get_swing_mode().has_value()) if (call.get_swing_mode().has_value())
@@ -3984,28 +3763,11 @@ namespace esphome
void set_optimistic(bool optimistic) { this->_optimistic = optimistic; } void set_optimistic(bool optimistic) { this->_optimistic = optimistic; }
bool get_optimistic() { return this->_optimistic; } bool get_optimistic() { return this->_optimistic; }
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
void set_supported_modes(ClimateModeMask modes) { this->_supported_modes = modes; } void set_supported_modes(ClimateModeMask modes) { this->_supported_modes = modes; }
void set_supported_swing_modes(ClimateSwingModeMask modes) { this->_supported_swing_modes = modes; } void set_supported_swing_modes(ClimateSwingModeMask modes) { this->_supported_swing_modes = modes; }
void set_supported_presets(ClimatePresetMask presets) { this->_supported_presets = presets; } void set_supported_presets(ClimatePresetMask presets) { this->_supported_presets = presets; }
void set_custom_presets(std::initializer_list<const char *> presets) { this->_supported_custom_presets = presets; } void set_custom_presets(std::initializer_list<const char *> presets) { this->_supported_custom_presets = presets; }
void set_custom_fan_modes(std::initializer_list<const char *> modes) { this->_supported_custom_fan_modes = modes; } void set_custom_fan_modes(std::initializer_list<const char *> modes) { this->_supported_custom_fan_modes = modes; }
#else
void set_supported_modes(const std::set<ClimateMode> &modes) { this->_supported_modes = modes; }
std::set<ClimateMode> get_supported_modes() { return this->_supported_modes; }
void set_supported_swing_modes(const std::set<ClimateSwingMode> &modes) { this->_supported_swing_modes = modes; }
std::set<ClimateSwingMode> get_supported_swing_modes() { return this->_supported_swing_modes; }
void set_supported_presets(const std::set<ClimatePreset> &presets) { this->_supported_presets = presets; }
const std::set<climate::ClimatePreset> &get_supported_presets() { return this->_supported_presets; }
void set_custom_presets(const std::set<std::string> &presets) { this->_supported_custom_presets = presets; }
const std::set<std::string> &get_supported_custom_presets() { return this->_supported_custom_presets; }
void set_custom_fan_modes(const std::set<std::string> &modes) { this->_supported_custom_fan_modes = modes; }
const std::set<std::string> &get_supported_custom_fan_modes() { return this->_supported_custom_fan_modes; }
#endif
#if defined(PRESETS_SAVING) #if defined(PRESETS_SAVING)
void set_store_settings(bool store_settings) { this->_store_settings = store_settings; } void set_store_settings(bool store_settings) { this->_store_settings = store_settings; }
@@ -4023,13 +3785,7 @@ namespace esphome
// заполнение шаблона параметров отображения виджета // заполнение шаблона параметров отображения виджета
// GK: всё же похоже правильнее это делать тут, а не в initAC() // GK: всё же похоже правильнее это делать тут, а не в initAC()
// initAC() в формируемом питоном коде вызывается до вызова aux_ac.set_supported_***() с установленными пользователем в конфиге параметрами // initAC() в формируемом питоном коде вызывается до вызова aux_ac.set_supported_***() с установленными пользователем в конфиге параметрами
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
_traits.add_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE); _traits.add_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE);
// NOT setting CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE - this device uses single target temperature
#else
_traits.set_supports_current_temperature(true);
_traits.set_supports_two_point_target_temperature(false); // if the climate device's target temperature should be split in target_temperature_low and target_temperature_high instead of just the single target_temperature
#endif
_traits.set_supported_modes(this->_supported_modes); _traits.set_supported_modes(this->_supported_modes);
_traits.set_supported_swing_modes(this->_supported_swing_modes); _traits.set_supported_swing_modes(this->_supported_swing_modes);
@@ -4058,14 +3814,10 @@ namespace esphome
//_traits.add_supported_preset(ClimatePreset::CLIMATE_PRESET_SLEEP); //_traits.add_supported_preset(ClimatePreset::CLIMATE_PRESET_SLEEP);
// if the climate device supports reporting the active current action of the device with the action property. // if the climate device supports reporting the active current action of the device with the action property.
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
if (this->_show_action) if (this->_show_action)
{ {
_traits.add_feature_flags(climate::CLIMATE_SUPPORTS_ACTION); _traits.add_feature_flags(climate::CLIMATE_SUPPORTS_ACTION);
} }
#else
_traits.set_supports_action(this->_show_action);
#endif
}; };
void loop() override void loop() override

View File

@@ -34,7 +34,7 @@ from esphome.components.climate import (
ClimateSwingMode, ClimateSwingMode,
) )
AUX_AC_FIRMWARE_VERSION = '0.3.2' AUX_AC_FIRMWARE_VERSION = '0.3.3'
AC_PACKET_TIMEOUT_MIN = 150 AC_PACKET_TIMEOUT_MIN = 150
AC_PACKET_TIMEOUT_MAX = 600 AC_PACKET_TIMEOUT_MAX = 600
AC_POWER_LIMIT_MIN = 30 AC_POWER_LIMIT_MIN = 30
@@ -128,12 +128,6 @@ AirConPowerLimitationOnAction = aux_ac_ns.class_(
) )
def use_new_api():
esphome_current_version = tuple(map(int, __version__.split('.')))
esphome_bc_version = tuple(map(int, "2025.11.0".split('.')))
return esphome_current_version >= esphome_bc_version
def validate_packet_timeout(value): def validate_packet_timeout(value):
minV = AC_PACKET_TIMEOUT_MIN minV = AC_PACKET_TIMEOUT_MIN
maxV = AC_PACKET_TIMEOUT_MAX maxV = AC_PACKET_TIMEOUT_MAX
@@ -433,16 +427,6 @@ async def to_code(config):
cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES])) cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES]))
if CONF_SUPPORTED_PRESETS in config: if CONF_SUPPORTED_PRESETS in config:
cg.add(var.set_supported_presets(config[CONF_SUPPORTED_PRESETS])) cg.add(var.set_supported_presets(config[CONF_SUPPORTED_PRESETS]))
if use_new_api():
if CONF_CUSTOM_PRESETS in config:
presets = config[CONF_CUSTOM_PRESETS]
c_str_presets = [cg.RawExpression(f"aux_ac::Constants::{p}.c_str()") for p in presets]
cg.add(var.set_custom_presets(c_str_presets))
if CONF_CUSTOM_FAN_MODES in config:
fan_modes = config[CONF_CUSTOM_FAN_MODES]
c_str_fan_modes = [cg.RawExpression(f"aux_ac::Constants::{p}.c_str()") for p in fan_modes]
cg.add(var.set_custom_fan_modes(c_str_fan_modes))
else:
if CONF_CUSTOM_PRESETS in config: if CONF_CUSTOM_PRESETS in config:
cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS])) cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS]))
if CONF_CUSTOM_FAN_MODES in config: if CONF_CUSTOM_FAN_MODES in config: