mirror of
https://github.com/GrKoR/esphome_aux_ac_component.git
synced 2025-12-06 11:36:55 +03:00
v.0.2.9 (inverter power limitaption) - first commit
This commit is contained in:
@@ -154,5 +154,33 @@ class AirConSendTestPacketAction : public Action<Ts...> {
|
||||
std::vector<uint8_t> data_static_{};
|
||||
};
|
||||
|
||||
// **************************************** POWER LIMITATION ACTIONS ****************************************
|
||||
template <typename... Ts>
|
||||
class AirConPowerLimitationOffAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit AirConPowerLimitationOffAction(AirCon *ac) : ac_(ac) {}
|
||||
|
||||
void play(Ts... x) override { this->ac_->powerLimitationOffSequence(); }
|
||||
|
||||
protected:
|
||||
AirCon *ac_;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
class AirConPowerLimitationOnAction : public Action<Ts...> {
|
||||
public:
|
||||
AirConPowerLimitationOnAction(AirCon *ac) : ac_(ac) {}
|
||||
TEMPLATABLE_VALUE(uint8_t, value);
|
||||
|
||||
void play(Ts... x) {
|
||||
this->pwr_lim_ = this->value_.value(x...);
|
||||
this->ac_->powerLimitationOnSequence(this->pwr_lim_);
|
||||
}
|
||||
|
||||
protected:
|
||||
AirCon *ac_;
|
||||
uint8_t pwr_lim_;
|
||||
};
|
||||
|
||||
} // namespace aux_ac
|
||||
} // namespace esphome
|
||||
@@ -56,13 +56,17 @@ class Constants {
|
||||
/// шаг изменения целевой температуры, градусы Цельсия
|
||||
static const float AC_TEMPERATURE_STEP;
|
||||
|
||||
/// минимальное и максимальное значение мощности инвертора при установке ограничений
|
||||
static const uint8_t AC_MIN_INVERTER_POWER_LIMIT;
|
||||
static const uint8_t AC_MAX_INVERTER_POWER_LIMIT;
|
||||
|
||||
// периодичность опроса кондиционера на предмет изменения состояния
|
||||
// изменение параметров с пульта не сообщается в UART, поэтому надо запрашивать состояние, чтобы быть в курсе
|
||||
// значение в миллисекундах
|
||||
static const uint32_t AC_STATES_REQUEST_INTERVAL;
|
||||
};
|
||||
|
||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.8";
|
||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.9 dev";
|
||||
|
||||
// custom fan modes
|
||||
const std::string Constants::MUTE = "mute";
|
||||
@@ -77,6 +81,8 @@ const std::string Constants::ANTIFUNGUS = "Antifungus";
|
||||
const float Constants::AC_MIN_TEMPERATURE = 16.0;
|
||||
const float Constants::AC_MAX_TEMPERATURE = 32.0;
|
||||
const float Constants::AC_TEMPERATURE_STEP = 0.5;
|
||||
const uint8_t Constants::AC_MIN_INVERTER_POWER_LIMIT = 30; // 30%
|
||||
const uint8_t Constants::AC_MAX_INVERTER_POWER_LIMIT = 100; // 100%
|
||||
const uint32_t Constants::AC_STATES_REQUEST_INTERVAL = 7000;
|
||||
|
||||
class AirCon;
|
||||
@@ -319,20 +325,50 @@ struct packet_big_info_body_t {
|
||||
// тело малого информационного пакета
|
||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11
|
||||
struct packet_small_info_body_t {
|
||||
// байт 8 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b08
|
||||
uint8_t byte_01;
|
||||
|
||||
// байт 9 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b09
|
||||
uint8_t cmd_answer;
|
||||
|
||||
// байт 10 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b10
|
||||
uint8_t target_temp_int_and_v_louver;
|
||||
|
||||
// байт 11 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b11
|
||||
uint8_t h_louver;
|
||||
|
||||
// байт 12 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b12
|
||||
uint8_t target_temp_frac;
|
||||
|
||||
// байт 13 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b13
|
||||
uint8_t fan_speed;
|
||||
|
||||
// байт 14 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b14
|
||||
uint8_t fan_turbo_and_mute;
|
||||
|
||||
// байт 15 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b15
|
||||
uint8_t mode;
|
||||
|
||||
// байт 16 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b16
|
||||
uint8_t zero1; // всегда 0x00
|
||||
|
||||
// байт 17 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b17
|
||||
uint8_t zero2; // всегда 0x00
|
||||
|
||||
// байт 18 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b18
|
||||
uint8_t status;
|
||||
|
||||
// байт 19 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b19
|
||||
uint8_t zero3; // всегда 0x00
|
||||
|
||||
// байт 20 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b20
|
||||
uint8_t display_and_mildew;
|
||||
uint8_t zero4; // всегда 0x00
|
||||
|
||||
// байт 21 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b21
|
||||
bool inverter_power_limitation_enable : 1;
|
||||
uint8_t inverter_power_limitation_value : 7;
|
||||
|
||||
// байт 22 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b22
|
||||
uint8_t target_temp_frac2;
|
||||
};
|
||||
|
||||
@@ -475,6 +511,10 @@ enum ac_mildew : uint8_t { AC_MILDEW_OFF = 0x00,
|
||||
// GK: define убрал, т.к. считаю, что сбрасывать счетчик не надо.
|
||||
// #define AC_MIN_COUNTER_MASK 0b00111111
|
||||
|
||||
// маски ограничения мощности для инверторного кондиционера
|
||||
#define AC_INVERTER_POWER_LIMITATION_ENABLE_MASK 0b10000000
|
||||
#define AC_INVERTER_POWER_LIMITATION_VALUE_MASK 0b01111111
|
||||
|
||||
// положение вертикальных жалюзи для фронтенда
|
||||
enum ac_vlouver_frontend : uint8_t {
|
||||
AC_VLOUVER_FRONTEND_SWING = 0x00,
|
||||
@@ -546,6 +586,8 @@ struct ac_command_t {
|
||||
ac_realFan realFanSpeed; // текущая скорость вентилятора
|
||||
uint8_t invertor_power; // мощность инвертора
|
||||
bool defrost; // режим разморозки внешнего блока (накопление тепла + прогрев испарителя)
|
||||
bool inverter_power_limitation_enable; // ограничение мощности инвертора
|
||||
uint8_t inverter_power_limitation_value; // значение ограничения мощности инвертора
|
||||
};
|
||||
|
||||
typedef ac_command_t ac_state_t; // текущее состояние параметров кондея можно хранить в таком же формате, как и комманды
|
||||
@@ -713,13 +755,6 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
// сырые данные последних полученных большого и маленького информационных пакетов
|
||||
ac_last_raw_data _last_raw_data;
|
||||
|
||||
// последовательность пакетов текущий шаг в последовательности
|
||||
sequence_item_t _sequence[AC_SEQUENCE_MAX_LEN];
|
||||
uint8_t _sequence_current_step;
|
||||
|
||||
// флаг успешного выполнения стартовой последовательности команд
|
||||
bool _startupSequenceComlete = false;
|
||||
|
||||
// нормализация показаний температуры, приведение в диапазон
|
||||
float _temp_target_normalise(float temp) {
|
||||
auto traits = this->get_traits();
|
||||
@@ -732,6 +767,20 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
return temp;
|
||||
}
|
||||
|
||||
// нормализация лимита ограничения мощности инвертора, приведение в диапазон
|
||||
uint8_t _power_limitation_value_normalise(uint8_t power_limitation_value) {
|
||||
if (power_limitation_value < Constants::AC_MIN_INVERTER_POWER_LIMIT) power_limitation_value = Constants::AC_MIN_INVERTER_POWER_LIMIT;
|
||||
if (power_limitation_value > Constants::AC_MAX_INVERTER_POWER_LIMIT) power_limitation_value = Constants::AC_MAX_INVERTER_POWER_LIMIT;
|
||||
return power_limitation_value;
|
||||
}
|
||||
|
||||
// последовательность пакетов текущий шаг в последовательности
|
||||
sequence_item_t _sequence[AC_SEQUENCE_MAX_LEN];
|
||||
uint8_t _sequence_current_step;
|
||||
|
||||
// флаг успешного выполнения стартовой последовательности команд
|
||||
bool _startupSequenceComlete = false;
|
||||
|
||||
// очистка последовательности команд
|
||||
void _clearSequence() {
|
||||
for (uint8_t i = 0; i < AC_SEQUENCE_MAX_LEN; i++) {
|
||||
@@ -909,6 +958,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
cmd->realFanSpeed = AC_REAL_FAN_UNTOUCHED;
|
||||
cmd->invertor_power = 0;
|
||||
cmd->defrost = false;
|
||||
cmd->inverter_power_limitation_enable =false;
|
||||
cmd->inverter_power_limitation_value = 0;
|
||||
};
|
||||
|
||||
// очистка буфера размером AC_BUFFER_SIZE
|
||||
@@ -1238,6 +1289,16 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.mildew != (ac_mildew)stateByte);
|
||||
_current_ac_state.mildew = (ac_mildew)stateByte;
|
||||
|
||||
// enable flag of power limitation for inverter ACs
|
||||
bool temp = small_info_body->inverter_power_limitation_enable;
|
||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.inverter_power_limitation_enable != temp);
|
||||
_current_ac_state.inverter_power_limitation_enable = temp;
|
||||
|
||||
// the limit value of power limitation for inverter ACs
|
||||
stateByte = small_info_body->inverter_power_limitation_value;
|
||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.inverter_power_limitation_value != stateByte);
|
||||
_current_ac_state.inverter_power_limitation_value = stateByte;
|
||||
|
||||
// уведомляем об изменении статуса сплита
|
||||
if (stateChangedFlag) stateChanged();
|
||||
|
||||
@@ -1309,8 +1370,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
|
||||
case AC_CMD_SET_PARAMS: { // такой статусный пакет присылается кондиционером в ответ на команду установки параметров
|
||||
// в теле пакета нет ничего примечательного
|
||||
// в байтах 2 и 3 тела похоже передается CRC пакета поступившей команды, на которую сплит отвечает
|
||||
// но я решил этот момент тут не проверять и не контролировать.
|
||||
// в байтах 2 и 3 тела передается CRC пакета поступившей команды, на которую сплит отвечает
|
||||
// я решил этот момент тут не проверять и не контролировать.
|
||||
// корректную установку параметров можно определить, запросив статус кондиционера сразу после получения этой команды кондея
|
||||
// в настоящий момент проверка сделана в механизме sequences
|
||||
break;
|
||||
@@ -1604,6 +1665,11 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
}
|
||||
}
|
||||
|
||||
// ограничение мощности инвертора
|
||||
pack->body[13] = (pack->body[13] & ~AC_INVERTER_POWER_LIMITATION_ENABLE_MASK) | cmd->inverter_power_limitation_enable;
|
||||
cmd->inverter_power_limitation_value = _power_limitation_value_normalise(cmd->inverter_power_limitation_value);
|
||||
pack->body[13] = (pack->body[13] & ~AC_INVERTER_POWER_LIMITATION_VALUE_MASK) | cmd->inverter_power_limitation_value;
|
||||
|
||||
// обнулить счетчик минут с последней команды
|
||||
// GK: считаю, что так делать не надо. Штатный wifi-модуль не сбрасывает счетчик минут.
|
||||
// pack->body[4] &= ~ AC_MIN_COUNTER_MASK ;
|
||||
@@ -1874,6 +1940,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
esphome::binary_sensor::BinarySensor *sensor_display_ = nullptr;
|
||||
esphome::binary_sensor::BinarySensor *sensor_defrost_ = nullptr;
|
||||
esphome::text_sensor::TextSensor *sensor_preset_reporter_ = nullptr;
|
||||
esphome::sensor::Sensor *sensor_invertor_power_limit_value_ = nullptr;
|
||||
esphome::binary_sensor::BinarySensor *sensor_invertor_power_limit_state_ = nullptr;
|
||||
|
||||
// загружает на выполнение последовательность команд на включение/выключение табло с температурой
|
||||
bool _displaySequence(ac_display dsp = AC_DISPLAY_ON) {
|
||||
@@ -1991,6 +2059,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
void set_display_sensor(binary_sensor::BinarySensor *display_sensor) { sensor_display_ = display_sensor; }
|
||||
void set_invertor_power_sensor(sensor::Sensor *invertor_power_sensor) { sensor_invertor_power_ = invertor_power_sensor; }
|
||||
void set_preset_reporter_sensor(text_sensor::TextSensor *preset_reporter_sensor) { sensor_preset_reporter_ = preset_reporter_sensor; }
|
||||
void set_invertor_power_limit_value_sensor(sensor::Sensor *invertor_power_limit_value_sensor) { sensor_invertor_power_limit_value_ = invertor_power_limit_value_sensor; }
|
||||
void set_invertor_power_limit_state_sensor(binary_sensor::BinarySensor *invertor_power_limit_state_sensor) { sensor_invertor_power_limit_state_ = invertor_power_limit_state_sensor; }
|
||||
|
||||
bool get_hw_initialized() { return _hw_initialized; };
|
||||
bool get_has_connection() { return _has_connection; };
|
||||
@@ -2314,6 +2384,12 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
// положение вертикальных жалюзи
|
||||
if (sensor_vlouver_state_ != nullptr)
|
||||
sensor_vlouver_state_->publish_state((float)this->getCurrentVlouverFrontendState());
|
||||
// флаг включенного ограничения мощности инвертора
|
||||
if (sensor_invertor_power_limit_state_ != nullptr)
|
||||
sensor_invertor_power_limit_state_->publish_state(_current_ac_state.inverter_power_limitation_enable);
|
||||
// значение ограничения мощности инвертора
|
||||
if (sensor_invertor_power_limit_value_ != nullptr)
|
||||
sensor_invertor_power_limit_value_->publish_state(_current_ac_state.inverter_power_limitation_value);
|
||||
|
||||
// сенсор состояния сплита
|
||||
if (sensor_preset_reporter_ != nullptr) {
|
||||
@@ -2965,6 +3041,53 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
return true;
|
||||
}
|
||||
|
||||
// выключает ограничение мощности сплита
|
||||
bool powerLimitationOffSequence() {
|
||||
// нет смысла в последовательности, если нет коннекта с кондиционером
|
||||
if (!get_has_connection()) {
|
||||
_debugMsg(F("powerLimitationOffSequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->_is_invertor) return false; // если кондиционер не инверторный, то выходим
|
||||
|
||||
// формируем команду
|
||||
ac_command_t cmd;
|
||||
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
|
||||
cmd.inverter_power_limitation_value = this->_current_ac_state.inverter_power_limitation_value;
|
||||
cmd.inverter_power_limitation_enable = false;
|
||||
// добавляем команду в последовательность
|
||||
if (!commandSequence(&cmd)) return false;
|
||||
|
||||
_debugMsg(F("powerLimitationOffSequence: loaded (value = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, cmd.inverter_power_limitation_enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
// включает ограничение мощности сплита на нужный уровень
|
||||
bool powerLimitationOnSequence(uint8_t power_limit = Constants::AC_MIN_INVERTER_POWER_LIMIT) {
|
||||
// нет смысла в последовательности, если нет коннекта с кондиционером
|
||||
if (!get_has_connection()) {
|
||||
_debugMsg(F("powerLimitationOnSequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->_is_invertor) return false; // если кондиционер не инверторный, то выходим
|
||||
|
||||
power_limit = this->_power_limitation_value_normalise(power_limit);
|
||||
|
||||
// формируем команду
|
||||
ac_command_t cmd;
|
||||
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
|
||||
cmd.inverter_power_limitation_enable = true;
|
||||
cmd.inverter_power_limitation_value = power_limit;
|
||||
// добавляем команду в последовательность
|
||||
if (!commandSequence(&cmd)) return false;
|
||||
|
||||
_debugMsg(F("powerLimitationOnSequence: loaded (power limit = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, power_limit);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// конвертирует состояние жалюзи из кодов сплита в коды для фронтенда
|
||||
ac_vlouver_frontend AUXvlouverToVlouverFrontend(const ac_louver_V vLouver) {
|
||||
switch (vLouver) {
|
||||
@@ -3048,7 +3171,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
// добавляем команду в последовательность
|
||||
if (!commandSequence(&cmd)) return false;
|
||||
|
||||
_debugMsg(F("setVLouverSequence: loaded (power = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, vLouver);
|
||||
_debugMsg(F("setVLouverSequence: loaded (vLouver = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, vLouver);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,16 +5,17 @@ from esphome.components import climate, uart, sensor, binary_sensor, text_sensor
|
||||
from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_UART_ID,
|
||||
CONF_PERIOD,
|
||||
CONF_CUSTOM_FAN_MODES,
|
||||
CONF_CUSTOM_PRESETS,
|
||||
CONF_INTERNAL,
|
||||
CONF_DATA,
|
||||
CONF_ID,
|
||||
CONF_INTERNAL,
|
||||
CONF_PERIOD,
|
||||
CONF_POSITION,
|
||||
CONF_SUPPORTED_MODES,
|
||||
CONF_SUPPORTED_SWING_MODES,
|
||||
CONF_SUPPORTED_PRESETS,
|
||||
CONF_UART_ID,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
ICON_POWER,
|
||||
@@ -22,7 +23,6 @@ from esphome.const import (
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
CONF_POSITION,
|
||||
)
|
||||
from esphome.components.climate import (
|
||||
ClimateMode,
|
||||
@@ -37,26 +37,41 @@ DEPENDENCIES = ["climate", "uart"]
|
||||
AUTO_LOAD = ["sensor", "binary_sensor", "text_sensor"]
|
||||
|
||||
CONF_SHOW_ACTION = "show_action"
|
||||
|
||||
CONF_INDOOR_TEMPERATURE = "indoor_temperature"
|
||||
CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature"
|
||||
ICON_OUTDOOR_TEMPERATURE = "mdi:home-thermometer-outline"
|
||||
|
||||
CONF_INBOUND_TEMPERATURE = "inbound_temperature"
|
||||
ICON_INBOUND_TEMPERATURE = "mdi:thermometer-plus"
|
||||
|
||||
CONF_OUTBOUND_TEMPERATURE = "outbound_temperature"
|
||||
ICON_OUTBOUND_TEMPERATURE = "mdi:thermometer-minus"
|
||||
|
||||
CONF_COMPRESSOR_TEMPERATURE = "compressor_temperature"
|
||||
ICON_COMPRESSOR_TEMPERATURE = "mdi:thermometer-lines"
|
||||
|
||||
CONF_DISPLAY_STATE = "display_state"
|
||||
CONF_INVERTOR_POWER = "invertor_power"
|
||||
|
||||
CONF_DEFROST_STATE = "defrost_state"
|
||||
ICON_DEFROST = "mdi:snowflake-melt"
|
||||
|
||||
CONF_DISPLAY_INVERTED = "display_inverted"
|
||||
ICON_DISPLAY = "mdi:clock-digital"
|
||||
|
||||
CONF_PRESET_REPORTER = "preset_reporter"
|
||||
ICON_PRESET_REPORTER = "mdi:format-list-group"
|
||||
|
||||
CONF_VLOUVER_STATE = "vlouver_state"
|
||||
ICON_VLOUVER_STATE = "mdi:compare-vertical"
|
||||
|
||||
CONF_LIMIT = "limit"
|
||||
CONF_INVERTER_POWER_LIMIT_VALUE = "inverter_power_limit_value"
|
||||
ICON_INVERTER_POWER_LIMIT_VALUE = "mdi:meter-electric-outline"
|
||||
CONF_INVERTER_POWER_LIMIT_STATE = "inverter_power_limit_state"
|
||||
ICON_INVERTER_POWER_LIMIT_STATE = "mdi:meter-electric-outline"
|
||||
|
||||
|
||||
aux_ac_ns = cg.esphome_ns.namespace("aux_ac")
|
||||
AirCon = aux_ac_ns.class_("AirCon", climate.Climate, cg.Component)
|
||||
@@ -89,8 +104,18 @@ AirConVLouverMiddleBelowAction = aux_ac_ns.class_(
|
||||
AirConVLouverBottomAction = aux_ac_ns.class_(
|
||||
"AirConVLouverBottomAction", automation.Action
|
||||
)
|
||||
AirConVLouverSetAction = aux_ac_ns.class_(
|
||||
"AirConVLouverSetAction", automation.Action
|
||||
)
|
||||
|
||||
# power limitation actions
|
||||
AirConPowerLimitationOffAction = aux_ac_ns.class_(
|
||||
"AirConPowerLimitationOffAction", automation.Action
|
||||
)
|
||||
AirConPowerLimitationOnAction = aux_ac_ns.class_(
|
||||
"AirConPowerLimitationOnAction", automation.Action
|
||||
)
|
||||
|
||||
AirConVLouverSetAction = aux_ac_ns.class_("AirConVLouverSetAction", automation.Action)
|
||||
|
||||
ALLOWED_CLIMATE_MODES = {
|
||||
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
|
||||
@@ -240,6 +265,24 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_INVERTER_POWER_LIMIT_VALUE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_PERCENT,
|
||||
icon=ICON_INVERTER_POWER_LIMIT_VALUE,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_POWER_FACTOR,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_INVERTER_POWER_LIMIT_STATE): binary_sensor.binary_sensor_schema(
|
||||
icon=ICON_INVERTER_POWER_LIMIT_STATE,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_SUPPORTED_MODES): cv.ensure_list(validate_modes),
|
||||
cv.Optional(CONF_SUPPORTED_SWING_MODES): cv.ensure_list(
|
||||
validate_swing_modes
|
||||
@@ -317,6 +360,16 @@ async def to_code(config):
|
||||
sens = await text_sensor.new_text_sensor(conf)
|
||||
cg.add(var.set_preset_reporter_sensor(sens))
|
||||
|
||||
if CONF_INVERTER_POWER_LIMIT_VALUE in config:
|
||||
conf = config[CONF_INVERTER_POWER_LIMIT_VALUE]
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_invertor_power_limit_value_sensor(sens))
|
||||
|
||||
if CONF_INVERTER_POWER_LIMIT_STATE in config:
|
||||
conf = config[CONF_INVERTER_POWER_LIMIT_STATE]
|
||||
sens = await binary_sensor.new_binary_sensor(conf)
|
||||
cg.add(var.set_invertor_power_limit_state_sensor(sens))
|
||||
|
||||
cg.add(var.set_period(config[CONF_PERIOD].total_milliseconds))
|
||||
cg.add(var.set_show_action(config[CONF_SHOW_ACTION]))
|
||||
cg.add(var.set_display_inverted(config[CONF_DISPLAY_INVERTED]))
|
||||
@@ -332,13 +385,13 @@ async def to_code(config):
|
||||
cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES]))
|
||||
|
||||
|
||||
|
||||
DISPLAY_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.display_off", AirConDisplayOffAction, DISPLAY_ACTION_SCHEMA
|
||||
)
|
||||
@@ -346,7 +399,6 @@ async def display_off_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.display_on", AirConDisplayOnAction, DISPLAY_ACTION_SCHEMA
|
||||
)
|
||||
@@ -355,13 +407,13 @@ async def display_on_to_code(config, action_id, template_arg, args):
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
|
||||
VLOUVER_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_stop", AirConVLouverStopAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -369,7 +421,6 @@ async def vlouver_stop_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_swing", AirConVLouverSwingAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -377,7 +428,6 @@ async def vlouver_swing_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_top", AirConVLouverTopAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -385,7 +435,6 @@ async def vlouver_top_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_middle_above", AirConVLouverMiddleAboveAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -393,7 +442,6 @@ async def vlouver_middle_above_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_middle", AirConVLouverMiddleAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -401,7 +449,6 @@ async def vlouver_middle_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_middle_below", AirConVLouverMiddleBelowAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -409,7 +456,6 @@ async def vlouver_middle_below_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_bottom", AirConVLouverBottomAction, VLOUVER_ACTION_SCHEMA
|
||||
)
|
||||
@@ -418,6 +464,7 @@ async def vlouver_bottom_to_code(config, action_id, template_arg, args):
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
|
||||
VLOUVER_SET_ACTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||
@@ -425,7 +472,6 @@ VLOUVER_SET_ACTION_SCHEMA = cv.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.vlouver_set", AirConVLouverSetAction, VLOUVER_SET_ACTION_SCHEMA
|
||||
)
|
||||
@@ -437,6 +483,43 @@ async def vlouver_set_to_code(config, action_id, template_arg, args):
|
||||
return var
|
||||
|
||||
|
||||
|
||||
POWER_LIMITATION_OFF_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||
}
|
||||
)
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.power_limit_off", AirConPowerLimitationOffAction, POWER_LIMITATION_OFF_ACTION_SCHEMA
|
||||
)
|
||||
async def power_limit_off_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
|
||||
POWER_LIMITATION_ON_ACTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||
cv.Optional(CONF_LIMIT, default=Capabilities.AC_MIN_INVERTER_POWER_LIMIT): cv.templatable(
|
||||
cv.int_range(30, 100)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@automation.register_action(
|
||||
"aux_ac.power_limit_on", AirConPowerLimitationOnAction, POWER_LIMITATION_ON_ACTION_SCHEMA
|
||||
)
|
||||
async def power_limit_on_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
template_ = await cg.templatable(config[CONF_LIMIT], args, int)
|
||||
cg.add(var.set_value(template_))
|
||||
return var
|
||||
|
||||
|
||||
|
||||
# *********************************************************************************************************
|
||||
# ВАЖНО! Только для инженеров!
|
||||
# Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт
|
||||
|
||||
162
tests/test-ext-power-limit.yaml
Normal file
162
tests/test-ext-power-limit.yaml
Normal file
@@ -0,0 +1,162 @@
|
||||
external_components:
|
||||
- source: github://GrKoR/esphome_aux_ac_component@dev
|
||||
components: [ aux_ac ]
|
||||
refresh: 0s
|
||||
|
||||
substitutions:
|
||||
devicename: test_local_airflow_dir
|
||||
upper_devicename: Test AUX
|
||||
|
||||
esphome:
|
||||
name: $devicename
|
||||
platform: ESP8266
|
||||
board: esp12e
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_pass
|
||||
manual_ip:
|
||||
static_ip: !secret wifi_ip
|
||||
gateway: !secret wifi_gateway
|
||||
subnet: !secret wifi_subnet
|
||||
dns1: 8.8.8.8
|
||||
dns2: 1.1.1.1
|
||||
reboot_timeout: 0s
|
||||
ap:
|
||||
ssid: Test AUX Fallback Hotspot
|
||||
password: !secret wifi_ap_pass
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 0
|
||||
|
||||
api:
|
||||
password: !secret api_pass
|
||||
reboot_timeout: 0s
|
||||
|
||||
ota:
|
||||
password: !secret ota_pass
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
|
||||
uart:
|
||||
id: ac_uart_bus
|
||||
tx_pin: GPIO1
|
||||
rx_pin: GPIO3
|
||||
baud_rate: 4800
|
||||
data_bits: 8
|
||||
parity: EVEN
|
||||
stop_bits: 1
|
||||
|
||||
sensor:
|
||||
- platform: uptime
|
||||
name: Uptime Sensor
|
||||
|
||||
climate:
|
||||
- platform: aux_ac
|
||||
name: $upper_devicename
|
||||
id: aux_id
|
||||
uart_id: ac_uart_bus
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: true
|
||||
indoor_temperature:
|
||||
name: $upper_devicename Indoor Temperature
|
||||
id: ${devicename}_indoor_temp
|
||||
internal: false
|
||||
display_state:
|
||||
name: $upper_devicename Display State
|
||||
id: ${devicename}_display_state
|
||||
internal: false
|
||||
outdoor_temperature:
|
||||
name: $upper_devicename Outdoor Temperature
|
||||
id: ${devicename}_outdoor_temp
|
||||
internal: false
|
||||
outbound_temperature:
|
||||
name: $upper_devicename Colant Outbound Temperature
|
||||
id: ${devicename}_outbound_temp
|
||||
internal: false
|
||||
inbound_temperature:
|
||||
name: $upper_devicename Colant Inbound Temperature
|
||||
id: ${devicename}_inbound_temp
|
||||
internal: false
|
||||
compressor_temperature:
|
||||
name: $upper_devicename Compressor Temperature
|
||||
id: ${devicename}_strange_temp
|
||||
internal: false
|
||||
defrost_state:
|
||||
name: $upper_devicename Defrost State
|
||||
id: ${devicename}_defrost_state
|
||||
internal: false
|
||||
invertor_power:
|
||||
name: $upper_devicename Invertor Power
|
||||
id: ${devicename}_invertor_power
|
||||
internal: false
|
||||
preset_reporter:
|
||||
name: $upper_devicename Preset Reporter
|
||||
id: ${devicename}_preset_reporter
|
||||
internal: false
|
||||
inverter_power_limit_value:
|
||||
name: $upper_devicename Inverter Power Limit Value
|
||||
id: ${devicename}_inverter_power_limit_value
|
||||
internal: false
|
||||
inverter_power_limit_state:
|
||||
name: $upper_devicename Inverter Power Limit State
|
||||
id: ${devicename}_inverter_power_limit_state
|
||||
internal: false
|
||||
visual:
|
||||
min_temperature: 16
|
||||
max_temperature: 32
|
||||
temperature_step: 0.5
|
||||
supported_modes:
|
||||
- HEAT_COOL
|
||||
- COOL
|
||||
- HEAT
|
||||
- DRY
|
||||
- FAN_ONLY
|
||||
custom_fan_modes:
|
||||
- MUTE
|
||||
- TURBO
|
||||
supported_presets:
|
||||
- SLEEP
|
||||
custom_presets:
|
||||
- CLEAN
|
||||
- HEALTH
|
||||
- ANTIFUNGUS
|
||||
supported_swing_modes:
|
||||
- VERTICAL
|
||||
- HORIZONTAL
|
||||
- BOTH
|
||||
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit Off
|
||||
icon: "mdi:power-plug-off-outline"
|
||||
on_press:
|
||||
- aux_ac.power_limit_off: aux_id
|
||||
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit On Half
|
||||
icon: "mdi:fraction-one-half"
|
||||
on_press:
|
||||
- aux_ac.power_limit_on:
|
||||
id: aux_id
|
||||
limit: 50
|
||||
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit Value
|
||||
id: ${devicename}_ipower_limit_value
|
||||
icon: "mdi:battery-unknown"
|
||||
mode: "slider"
|
||||
min_value: 30
|
||||
max_value: 100
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- lambda: !lambda |-
|
||||
id(aux_id).powerLimitationOnSequence( x );
|
||||
|
||||
162
tests/test-local-power-limit.yaml
Normal file
162
tests/test-local-power-limit.yaml
Normal file
@@ -0,0 +1,162 @@
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: ../components
|
||||
|
||||
substitutions:
|
||||
devicename: test_local_airflow_dir
|
||||
upper_devicename: Test AUX
|
||||
|
||||
esphome:
|
||||
name: $devicename
|
||||
platform: ESP8266
|
||||
board: esp12e
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_pass
|
||||
manual_ip:
|
||||
static_ip: !secret wifi_ip
|
||||
gateway: !secret wifi_gateway
|
||||
subnet: !secret wifi_subnet
|
||||
dns1: 8.8.8.8
|
||||
dns2: 1.1.1.1
|
||||
reboot_timeout: 0s
|
||||
ap:
|
||||
ssid: Test AUX Fallback Hotspot
|
||||
password: !secret wifi_ap_pass
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 0
|
||||
|
||||
api:
|
||||
password: !secret api_pass
|
||||
reboot_timeout: 0s
|
||||
|
||||
ota:
|
||||
password: !secret ota_pass
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
|
||||
uart:
|
||||
id: ac_uart_bus
|
||||
tx_pin: GPIO1
|
||||
rx_pin: GPIO3
|
||||
baud_rate: 4800
|
||||
data_bits: 8
|
||||
parity: EVEN
|
||||
stop_bits: 1
|
||||
|
||||
sensor:
|
||||
- platform: uptime
|
||||
name: Uptime Sensor
|
||||
|
||||
climate:
|
||||
- platform: aux_ac
|
||||
name: $upper_devicename
|
||||
id: aux_id
|
||||
uart_id: ac_uart_bus
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: true
|
||||
indoor_temperature:
|
||||
name: $upper_devicename Indoor Temperature
|
||||
id: ${devicename}_indoor_temp
|
||||
internal: false
|
||||
display_state:
|
||||
name: $upper_devicename Display State
|
||||
id: ${devicename}_display_state
|
||||
internal: false
|
||||
outdoor_temperature:
|
||||
name: $upper_devicename Outdoor Temperature
|
||||
id: ${devicename}_outdoor_temp
|
||||
internal: false
|
||||
outbound_temperature:
|
||||
name: $upper_devicename Colant Outbound Temperature
|
||||
id: ${devicename}_outbound_temp
|
||||
internal: false
|
||||
inbound_temperature:
|
||||
name: $upper_devicename Colant Inbound Temperature
|
||||
id: ${devicename}_inbound_temp
|
||||
internal: false
|
||||
compressor_temperature:
|
||||
name: $upper_devicename Compressor Temperature
|
||||
id: ${devicename}_strange_temp
|
||||
internal: false
|
||||
defrost_state:
|
||||
name: $upper_devicename Defrost State
|
||||
id: ${devicename}_defrost_state
|
||||
internal: false
|
||||
invertor_power:
|
||||
name: $upper_devicename Invertor Power
|
||||
id: ${devicename}_invertor_power
|
||||
internal: false
|
||||
preset_reporter:
|
||||
name: $upper_devicename Preset Reporter
|
||||
id: ${devicename}_preset_reporter
|
||||
internal: false
|
||||
inverter_power_limit_value:
|
||||
name: $upper_devicename Inverter Power Limit Value
|
||||
id: ${devicename}_inverter_power_limit_value
|
||||
internal: false
|
||||
inverter_power_limit_state:
|
||||
name: $upper_devicename Inverter Power Limit State
|
||||
id: ${devicename}_inverter_power_limit_state
|
||||
internal: false
|
||||
visual:
|
||||
min_temperature: 16
|
||||
max_temperature: 32
|
||||
temperature_step: 0.5
|
||||
supported_modes:
|
||||
- HEAT_COOL
|
||||
- COOL
|
||||
- HEAT
|
||||
- DRY
|
||||
- FAN_ONLY
|
||||
custom_fan_modes:
|
||||
- MUTE
|
||||
- TURBO
|
||||
supported_presets:
|
||||
- SLEEP
|
||||
custom_presets:
|
||||
- CLEAN
|
||||
- HEALTH
|
||||
- ANTIFUNGUS
|
||||
supported_swing_modes:
|
||||
- VERTICAL
|
||||
- HORIZONTAL
|
||||
- BOTH
|
||||
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit Off
|
||||
icon: "mdi:power-plug-off-outline"
|
||||
on_press:
|
||||
- aux_ac.power_limit_off: aux_id
|
||||
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit On Half
|
||||
icon: "mdi:fraction-one-half"
|
||||
on_press:
|
||||
- aux_ac.power_limit_on:
|
||||
id: aux_id
|
||||
limit: 50
|
||||
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit Value
|
||||
id: ${devicename}_ipower_limit_value
|
||||
icon: "mdi:battery-unknown"
|
||||
mode: "slider"
|
||||
min_value: 30
|
||||
max_value: 100
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- lambda: !lambda |-
|
||||
id(aux_id).powerLimitationOnSequence( x );
|
||||
|
||||
Reference in New Issue
Block a user