mirror of
https://github.com/GrKoR/esphome_aux_ac_component.git
synced 2025-12-06 11:36:55 +03:00
+ new yaml parameter: packet timeout
This commit is contained in:
@@ -99,6 +99,7 @@ climate:
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: false
|
||||
timeout: 150
|
||||
indoor_temperature:
|
||||
name: AC Indoor Temperature
|
||||
id: ac_indoor_temp
|
||||
@@ -191,6 +192,11 @@ climate:
|
||||
|
||||
- **display_inverted** (*Optional*, boolean, default ``false``): It configures display driver logic level. As it turned out in the issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31), different models of conditioners manage display different way. Rovex ACs powers off display by bit `1` in command packet and power it on by bit `0`. Many other conditioners do this vice versa.
|
||||
|
||||
- **timeout** (*Optional*, unsigned integer, default ``150``): Packet timeout for `aux_ac` data receiver.
|
||||
In the most common use of `aux_ac`, it isn't necessary to change this value. This keyword is optional, so you may omit it.
|
||||
The only situation when you can play with timeout is heavily loaded ESP. When you are using your ESP for many hard tasks, it is possible that `aux_ac` does not have enough time to receive AC responses. In this case, you can slightly raise the timeout value. But the best solution would be to remove some of the tasks from the ESP.
|
||||
The timeout is limited to a range from `150` to `600` milliseconds. Other values are possible only with source code modification. But I don't recommend that.
|
||||
|
||||
- **indoor_temperature** (*Optional*): Parameters of the room air temperature sensor.
|
||||
- **name** (**Required**, string): The name for the temperature sensor.
|
||||
- **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas.
|
||||
|
||||
@@ -97,6 +97,7 @@ climate:
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: false
|
||||
timeout: 150
|
||||
indoor_temperature:
|
||||
name: AC Indoor Temperature
|
||||
id: ac_indoor_temp
|
||||
@@ -189,6 +190,11 @@ climate:
|
||||
|
||||
- **display_inverted** (*Опциональный*, логическое, по умолчанию ``false``): Настраивает способ управления дисплеем. Как выяснилось (issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31)), включение-выключение дисплея обрабатывается кондиционерами по разному. Кондиционеры Rovex включают дисплей по `0` в соответствующем бите команды и выключают по биту `1`. Многие другие модели кондиционеров поступают наоборот.
|
||||
|
||||
- **timeout** (*Опциональный*, неотрицательное целое, по умолчанию ``150``): Таймаут получения пакета для ресивера данных `aux_ac`.
|
||||
Чаще всего вам это значение никогда не понадобится. Поскольку этот параметр опционален, то его можно смело пропустить, если нет необходимости менять таймауты.
|
||||
Единственная ситуация, когда вам может пригодиться этот параметр, - это сильно загруженная ESP. Если по какой-то неподдающейся логике причине вы кроме `aux_ac` нагрузили свою ESP кучей дополнительных ресурсоемких задач, то у компонента может просто не хватать времени для оперативного приёма ответов от кондиционера. В этом в логе будут сообщения о том, что последовательность команд была прервана по таймауту. Чтобы это исправить, лучше, конечно, немного разгрузить ESP. Если это вам не подходит, тогда можно увеличить таймаут.
|
||||
Значение таймаута в прошивке ограничено диапазоном от `150` до `600` миллисекунд. Устанавливать значения выше можно только отредактировав исходные коды компонента. Но сильно задирать таймаут не стоит. Кондиционер периодически рассылает пакеты без запроса со стороны `aux_ac` и это приводит к сбою в отправке команды.
|
||||
|
||||
- **indoor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры воздуха, если такой датчик нужен
|
||||
- **name** (**Обязательный**, строка): Имя датчика температуры.
|
||||
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах.
|
||||
|
||||
@@ -64,9 +64,15 @@ class Constants {
|
||||
// изменение параметров с пульта не сообщается в UART, поэтому надо запрашивать состояние, чтобы быть в курсе
|
||||
// значение в миллисекундах
|
||||
static const uint32_t AC_STATES_REQUEST_INTERVAL;
|
||||
|
||||
// границы допустимого диапазона таймаута загрузки пакета
|
||||
// таймаут загрузки - через такое количиство миллисекунд конечный автомат перейдет из
|
||||
// состояния ACSM_RECEIVING_PACKET в ACSM_IDLE, если пакет не будет загружен
|
||||
static const uint32_t AC_PACKET_TIMEOUT_MAX;
|
||||
static const uint32_t AC_PACKET_TIMEOUT_MIN;
|
||||
};
|
||||
|
||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.9-dev.3+";
|
||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.9-dev.4";
|
||||
|
||||
// custom fan modes
|
||||
const std::string Constants::MUTE = "mute";
|
||||
@@ -84,6 +90,19 @@ 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;
|
||||
// таймаут загрузки пакета
|
||||
// По расчетам выходит:
|
||||
// - получение и обработка посимвольно не должна длиться дольше 600 мсек.
|
||||
// - получение и обработка пакетов целиком не должна длиться дольше 150 мсек.
|
||||
// Мы будем обрабатывать пакетами, поэтому 150.
|
||||
// Растягивать приём пакетов очередью команд нельзя, так как кондиционер иногда посылает
|
||||
// информационные пакеты без запроса. Такие пакеты будут рушить последовательность команд,
|
||||
// команды будут теряться. От такой коллизии мы не защищены в любом случае. Но чем меньше таймаут,
|
||||
// тем меньше шансов на коллизию.
|
||||
// Из этих соображений выбраны границы диапазона (_MIN и _MAX значения).
|
||||
const uint32_t Constants::AC_PACKET_TIMEOUT_MAX = 600;
|
||||
const uint32_t Constants::AC_PACKET_TIMEOUT_MIN = 150;
|
||||
|
||||
|
||||
class AirCon;
|
||||
|
||||
@@ -104,17 +123,6 @@ enum acsm_state : uint8_t {
|
||||
// поэтому буффер увеличен
|
||||
#define AC_BUFFER_SIZE 35
|
||||
|
||||
/**
|
||||
* таймаут загрузки пакета
|
||||
*
|
||||
* через такое количиство миллисекунд конечный автомат перейдет из состояния ACSM_RECEIVING_PACKET в ACSM_IDLE, если пакет не будет загружен
|
||||
* По расчетам выходит:
|
||||
* - получение и обработка посимвольно не должна длиться дольше 600 мсек.
|
||||
* - получение и обработка пакетов целиком не должна длиться дольше 150 мсек.
|
||||
* Мы будем обрабатывать пакетами.
|
||||
**/
|
||||
#define AC_PACKET_TIMEOUT 150
|
||||
|
||||
// типы пакетов
|
||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_types
|
||||
#define AC_PTYPE_PING 0x01 // ping-пакет
|
||||
@@ -753,6 +761,9 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
// пакет для тестирования всякой фигни
|
||||
packet_t _outTestPacket;
|
||||
|
||||
// таймаут загрузки пакета, по дефолту минимальный
|
||||
uint32_t _packet_timeout = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||
|
||||
// сырые данные последних полученных большого и маленького информационных пакетов
|
||||
ac_last_raw_data _last_raw_data;
|
||||
|
||||
@@ -1127,7 +1138,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
}
|
||||
|
||||
// если пакет не загружен, а время вышло, то надо вернуться в IDLE
|
||||
if (millis() - _inPacket.msec >= AC_PACKET_TIMEOUT) {
|
||||
if (millis() - _inPacket.msec >= this->_packet_timeout) {
|
||||
_debugMsg(F("Receiver: packet timed out!"), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
_debugPrintPacket(&_inPacket, ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
_clearInPacket();
|
||||
@@ -2031,6 +2042,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
_ac_serial = parent;
|
||||
_hw_initialized = (_ac_serial != nullptr);
|
||||
_has_connection = false;
|
||||
_packet_timeout = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||
|
||||
// заполняем структуру состояния начальными значениями
|
||||
_clearCommand((ac_command_t *)&_current_ac_state);
|
||||
@@ -2421,6 +2433,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
ESP_LOGCONFIG(TAG, " [x] Period: %dms", this->get_period());
|
||||
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] Packet timeout: %dms", this->get_packet_timeout());
|
||||
|
||||
#if defined(PRESETS_SAVING)
|
||||
ESP_LOGCONFIG(TAG, " [x] Save settings %s", TRUEFALSE(this->get_store_settings()));
|
||||
@@ -2428,17 +2441,18 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
|
||||
ESP_LOGCONFIG(TAG, " [?] Is inverter %s", millis() > _update_period + 1000 ? YESNO(_is_inverter) : "pending...");
|
||||
|
||||
LOG_SENSOR(" ", "Inverter Power", this->sensor_inverter_power_);
|
||||
LOG_SENSOR(" ", "Inverter Power Limit Value", this->sensor_inverter_power_limit_value_);
|
||||
LOG_BINARY_SENSOR(" ", "Inverter Power Limit State", this->sensor_inverter_power_limit_state_);
|
||||
|
||||
LOG_SENSOR(" ", "Indoor Temperature", this->sensor_indoor_temperature_);
|
||||
LOG_SENSOR(" ", "Outdoor Temperature", this->sensor_outdoor_temperature_);
|
||||
LOG_SENSOR(" ", "Inbound Temperature", this->sensor_inbound_temperature_);
|
||||
LOG_SENSOR(" ", "Outbound Temperature", this->sensor_outbound_temperature_);
|
||||
LOG_SENSOR(" ", "Compressor Temperature", this->sensor_compressor_temperature_);
|
||||
LOG_SENSOR(" ", "Inverter Power", this->sensor_inverter_power_);
|
||||
LOG_BINARY_SENSOR(" ", "Defrost Status", this->sensor_defrost_);
|
||||
LOG_BINARY_SENSOR(" ", "Display", this->sensor_display_);
|
||||
LOG_TEXT_SENSOR(" ", "Preset Reporter", this->sensor_preset_reporter_);
|
||||
LOG_SENSOR(" ", "Inverter Power Limit Value", this->sensor_inverter_power_limit_value_);
|
||||
LOG_BINARY_SENSOR(" ", "Inverter Power Limit State", this->sensor_inverter_power_limit_state_);
|
||||
this->dump_traits_(TAG);
|
||||
}
|
||||
|
||||
@@ -3207,6 +3221,13 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
void set_display_inverted(bool display_inverted) { this->_display_inverted = display_inverted; }
|
||||
bool get_display_inverted() { return this->_display_inverted; }
|
||||
|
||||
void set_packet_timeout(uint32_t ms) {
|
||||
if (ms < Constants::AC_PACKET_TIMEOUT_MIN) ms = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||
if (ms > Constants::AC_PACKET_TIMEOUT_MAX) ms = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||
this->_packet_timeout = ms;
|
||||
}
|
||||
uint32_t get_packet_timeout() { return this->_packet_timeout; }
|
||||
|
||||
// возможно функции get и не нужны, но вроде как должны быть
|
||||
void set_supported_modes(const std::set<ClimateMode> &modes) { this->_supported_modes = modes; }
|
||||
std::set<ClimateMode> get_supported_modes() { return this->_supported_modes; }
|
||||
|
||||
@@ -15,6 +15,7 @@ from esphome.const import (
|
||||
CONF_SUPPORTED_MODES,
|
||||
CONF_SUPPORTED_SWING_MODES,
|
||||
CONF_SUPPORTED_PRESETS,
|
||||
CONF_TIMEOUT,
|
||||
CONF_UART_ID,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
@@ -82,7 +83,7 @@ Capabilities = aux_ac_ns.namespace("Constants")
|
||||
AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action)
|
||||
AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action)
|
||||
|
||||
# test packet
|
||||
# test packet action
|
||||
AirConSendTestPacketAction = aux_ac_ns.class_(
|
||||
"AirConSendTestPacketAction", automation.Action
|
||||
)
|
||||
@@ -118,6 +119,26 @@ AirConPowerLimitationOnAction = aux_ac_ns.class_(
|
||||
)
|
||||
|
||||
|
||||
AC_PACKET_TIMEOUT_MIN = 150
|
||||
AC_PACKET_TIMEOUT_MAX = 600
|
||||
def validate_packet_timeout(value):
|
||||
minV = AC_PACKET_TIMEOUT_MIN
|
||||
maxV = AC_PACKET_TIMEOUT_MAX
|
||||
if value in range(minV, maxV+1):
|
||||
return cv.Schema(cv.uint32_t)(value)
|
||||
raise cv.Invalid(f"Timeout should be in range: {minV}..{maxV}.")
|
||||
|
||||
|
||||
AC_POWER_LIMIT_MIN = 30
|
||||
AC_POWER_LIMIT_MAX = 100
|
||||
def validate_power_limit_range(value):
|
||||
minV = AC_POWER_LIMIT_MIN
|
||||
maxV = AC_POWER_LIMIT_MAX
|
||||
if value in range(minV, maxV+1):
|
||||
return cv.Schema(cv.uint32_t)(value)
|
||||
raise cv.Invalid(f"Power limit should be in range: {minV}..{maxV}")
|
||||
|
||||
|
||||
ALLOWED_CLIMATE_MODES = {
|
||||
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
|
||||
"COOL": ClimateMode.CLIMATE_MODE_COOL,
|
||||
@@ -160,7 +181,7 @@ def validate_raw_data(value):
|
||||
|
||||
|
||||
def output_info(config):
|
||||
"""_LOGGER.info(config)"""
|
||||
"""_LOGGER.info(config.items())"""
|
||||
return config
|
||||
|
||||
|
||||
@@ -171,6 +192,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_PERIOD, default="7s"): cv.time_period,
|
||||
cv.Optional(CONF_SHOW_ACTION, default="true"): cv.boolean,
|
||||
cv.Optional(CONF_DISPLAY_INVERTED, default="false"): cv.boolean,
|
||||
cv.Optional(CONF_TIMEOUT, default=AC_PACKET_TIMEOUT_MIN): validate_packet_timeout,
|
||||
|
||||
cv.Optional(CONF_INVERTER_POWER_DEPRICATED): cv.invalid(
|
||||
"The name of sensor was changed in v.0.2.9 from 'invertor_power' to 'inverter_power'. Update your config please."
|
||||
@@ -307,8 +329,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
"""_LOGGER.info("--------------")"""
|
||||
"""_LOGGER.info(config)"""
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await climate.register_climate(var, config)
|
||||
@@ -379,6 +399,7 @@ async def to_code(config):
|
||||
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]))
|
||||
cg.add(var.set_packet_timeout(config[CONF_TIMEOUT]))
|
||||
if CONF_SUPPORTED_MODES in config:
|
||||
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
|
||||
if CONF_SUPPORTED_SWING_MODES in config:
|
||||
@@ -508,9 +529,7 @@ async def power_limit_off_to_code(config, action_id, template_arg, args):
|
||||
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)
|
||||
),
|
||||
cv.Optional(CONF_LIMIT, default=AC_POWER_LIMIT_MIN): validate_power_limit_range,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ climate:
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: true
|
||||
timeout: 150
|
||||
indoor_temperature:
|
||||
name: $upper_devicename Indoor Temperature
|
||||
id: ${devicename}_indoor_temp
|
||||
@@ -90,7 +91,7 @@ climate:
|
||||
id: ${devicename}_defrost_state
|
||||
internal: false
|
||||
inverter_power:
|
||||
name: $upper_devicename Invertor Power
|
||||
name: $upper_devicename Inverter Power
|
||||
id: ${devicename}_invertor_power
|
||||
internal: false
|
||||
preset_reporter:
|
||||
@@ -144,8 +145,7 @@ button:
|
||||
- aux_ac.power_limit_on:
|
||||
id: aux_id
|
||||
limit: 50
|
||||
|
||||
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit Value
|
||||
|
||||
@@ -61,6 +61,7 @@ climate:
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: true
|
||||
timeout: 150
|
||||
indoor_temperature:
|
||||
name: $upper_devicename Indoor Temperature
|
||||
id: ${devicename}_indoor_temp
|
||||
@@ -144,8 +145,7 @@ button:
|
||||
- aux_ac.power_limit_on:
|
||||
id: aux_id
|
||||
limit: 50
|
||||
|
||||
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
name: ${upper_devicename} IPower Limit Value
|
||||
|
||||
Reference in New Issue
Block a user