mirror of
https://github.com/GrKoR/esphome_aux_ac_component.git
synced 2025-12-16 16:37:06 +03:00
Merge pull request #33 from GrKoR:dev
release 0.2.2 - display control update
This commit is contained in:
@@ -85,6 +85,7 @@ climate:
|
||||
uart_id: ac_uart_bus
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: false
|
||||
indoor_temperature:
|
||||
name: AC Indoor Temperature
|
||||
id: ac_indoor_temp
|
||||
@@ -123,12 +124,13 @@ climate:
|
||||
- **name** (**Required**, string): The name of the climate device. At least one of `id` or `name` is required!
|
||||
- **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID used for code generation. At least one of `id` or `name` is required!
|
||||
- **uart_id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID of the [UART Bus](https://esphome.io/components/uart.html) if you want to use multiple UART buses.
|
||||
- **period** (*Optional*, [time](https://esphome.io/guides/configuration-types.html#config-time)): Period between status requests to the AC. Defaults to ``7s``. `Aux_ac` will receive the new air conditioner status only after a regular request, even if you change the settings of AC using IR-remote.
|
||||
- **show_action** (*Optional*, boolean): Whether to show current action of the device (experimental). For example in the HEAT-COOL mode AC hardware may be in one of the following actions:
|
||||
- **period** (*Optional*, [time](https://esphome.io/guides/configuration-types.html#config-time), default ``7s``): Period between status requests to the AC. `Aux_ac` will receive the new air conditioner status only after a regular request, even if you change the settings of AC using IR-remote.
|
||||
- **show_action** (*Optional*, boolean, default ``true``): Whether to show current action of the device (experimental). For example in the HEAT-COOL mode AC hardware may be in one of the following actions:
|
||||
- HEATING: AC is heating the air in the room;
|
||||
- IDLE: AC is working in the FAN mode cause the target temperature is reached;
|
||||
- COOLING: AC is cooling the air.
|
||||
The same thing will be in HEAT or COOL modes, with the only difference of the list of actions (IDLE + HEATING or IDLE + COOLING).
|
||||
- **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.
|
||||
- **indoor_temperature** (*Optional*): The information for the 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.
|
||||
|
||||
@@ -87,6 +87,7 @@ climate:
|
||||
uart_id: ac_uart_bus
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: false
|
||||
indoor_temperature:
|
||||
name: AC Indoor Temperature
|
||||
id: ac_indoor_temp
|
||||
@@ -125,12 +126,13 @@ climate:
|
||||
- **name** (**Обязательный**, строка): Имя кондиционера. Как минимум один из параметров `id` или `name` должен быть указан!
|
||||
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите идентификатор кондиционера чтобы обращаться к нему из кода. Как минимум один из параметров `id` или `name` должен быть указан!
|
||||
- **uart_id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите ID [шины UART](https://esphome.io/components/uart.html), к которой подключен кондиционер. Если сконфигурирована одна шина, то компонент подключит её автоматически. Если шин несколько, то лучше указать вручную.
|
||||
- **period** (*Опциональный*, [время](https://esphome.io/guides/configuration-types.html#config-time)): Период между запросами статуса кондиционера. По умолчанию ``7s``. `Aux_ac` получает новое состояние кондиционера только после регулярного запроса, потому что сам кондиционер об изменении параметров своеё работы не уведомляет. Поэтому нужно запрашивать его, вдруг пользователь установил иной режим работы с помощью ИК-пульта.
|
||||
- **show_action** (*Опциональный*, логическое): Показывать ли текущую задачу кондиционера (экспериментальная функция). Например, в режиме HEAT-COOL кондиционер может выполнять одну из следующих задач:
|
||||
- **period** (*Опциональный*, [время](https://esphome.io/guides/configuration-types.html#config-time), по умолчанию ``7s``): Период между запросами статуса кондиционера. `Aux_ac` получает новое состояние кондиционера только после регулярного запроса, потому что сам кондиционер об изменении параметров своеё работы не уведомляет. Поэтому нужно запрашивать его, вдруг пользователь установил иной режим работы с помощью ИК-пульта.
|
||||
- **show_action** (*Опциональный*, логическое, по умолчанию ``true``): Показывать ли текущую задачу кондиционера (экспериментальная функция). Например, в режиме HEAT-COOL кондиционер может выполнять одну из следующих задач:
|
||||
- НАГРЕВ: нагревает воздух в комнате;
|
||||
- ПРОСТОЙ: кондиционер работает в режиме вентилятора для перемешивания воздуха в комнате, поскольку целевая температура уже достигнута;
|
||||
- ОХЛАЖДЕНИЕ: кондиционер охлаждает воздух в комнате.
|
||||
Аналогично будут отображаться действия кондиционера и для режимов ОТОПЛЕНИЕ и ОХЛАЖДЕНИЕ. Единственная разница будет в количестве действий: ПРОСТОЙ+НАГРЕВ для режима отопления и ПРОСТОЙ+ОХЛАЖДЕНИЕ для режима охлаждения комнаты.
|
||||
- **display_inverted** (*Опциональный*, логическое, по умолчанию ``false``): Настраивает способ управления дисплеем. Как выяснилось (issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31)), включение-выключение дисплея обрабатывается кондиционерами по разному. Кондиционеры Rovex включают дисплей по `0` в соответствующем бите команды и выключают по биту `1`. Многие другие модели кондиционеров поступают наоборот.
|
||||
- **indoor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры воздуха, если такой датчик нужен
|
||||
- **name** (**Обязательный**, строка): Имя датчика температуры.
|
||||
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах.
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace aux_ac {
|
||||
public:
|
||||
explicit AirConDisplayOffAction(AirCon *ac) : ac_(ac) {}
|
||||
|
||||
void play(Ts... x) override { this->ac_->displaySequence(AC_DISPLAY_OFF); }
|
||||
void play(Ts... x) override { this->ac_->displayOffSequence(); }
|
||||
|
||||
protected:
|
||||
AirCon *ac_;
|
||||
@@ -25,7 +25,7 @@ namespace aux_ac {
|
||||
public:
|
||||
explicit AirConDisplayOnAction(AirCon *ac) : ac_(ac) {}
|
||||
|
||||
void play(Ts... x) override { this->ac_->displaySequence(AC_DISPLAY_ON); }
|
||||
void play(Ts... x) override { this->ac_->displayOnSequence(); }
|
||||
|
||||
protected:
|
||||
AirCon *ac_;
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
static const uint32_t AC_STATES_REQUEST_INTERVAL;
|
||||
};
|
||||
|
||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.1";
|
||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.2";
|
||||
const char *const Constants::TAG = "AirCon";
|
||||
const std::string Constants::MUTE = "mute";
|
||||
const std::string Constants::TURBO = "turbo";
|
||||
@@ -353,7 +353,7 @@ enum ac_fanmute : uint8_t { AC_FANMUTE_OFF = 0x00, AC_FANMUTE_ON = 0x80, AC_FANM
|
||||
|
||||
// включение-выключение дисплея на корпусе внутреннего блока
|
||||
#define AC_DISPLAY_MASK 0b00010000
|
||||
enum ac_display : uint8_t { AC_DISPLAY_ON = 0x00, AC_DISPLAY_OFF = 0x10, AC_DISPLAY_UNTOUCHED = 0xFF };
|
||||
enum ac_display : uint8_t { AC_DISPLAY_OFF = 0x00, AC_DISPLAY_ON = 0x10, AC_DISPLAY_UNTOUCHED = 0xFF };
|
||||
|
||||
// включение-выключение функции "Антиплесень".
|
||||
// По факту: после выключения сплита он оставляет минут на 5 открытые жалюзи и глушит вентилятор. Уличный блок при этом гудит и тарахтит.
|
||||
@@ -469,6 +469,11 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
// по дефолту показываем
|
||||
bool _show_action = true;
|
||||
|
||||
// как отрабатывается включание-выключение дисплея.
|
||||
// если тут false, то 1 в соответствующем бите включает дисплей, а 0 выключает.
|
||||
// если тут true, то 1 потушит дисплей, а 0 включит.
|
||||
bool _display_inverted = false;
|
||||
|
||||
// поддерживаемые кондиционером опции
|
||||
std::set<ClimateMode> _supported_modes{};
|
||||
std::set<ClimateSwingMode> _supported_swing_modes{};
|
||||
@@ -576,7 +581,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
return true;
|
||||
}
|
||||
|
||||
// додбавляет в последовательность шаг с задержкой
|
||||
// добавляет в последовательность шаг с задержкой
|
||||
bool _addSequenceDelayStep(uint16_t timeout){
|
||||
return this->_addSequenceStep(AC_SIT_DELAY, nullptr, nullptr, timeout);
|
||||
}
|
||||
@@ -718,9 +723,9 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
}
|
||||
|
||||
// копирует пакет из одной структуры в другую с корректным переносом указателей на заголовки и т.п.
|
||||
void _copyPacket(packet_t *dest, packet_t *src){
|
||||
if (dest == nullptr) return;
|
||||
if (src == nullptr) return;
|
||||
bool _copyPacket(packet_t *dest, packet_t *src){
|
||||
if (dest == nullptr) return false;
|
||||
if (src == nullptr) return false;
|
||||
|
||||
dest->msec = src->msec;
|
||||
dest->bytesLoaded = src->bytesLoaded;
|
||||
@@ -728,6 +733,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
dest->header = (packet_header_t *)&dest->data;
|
||||
if (dest->header->body_length > 0) dest->body = &dest->data[AC_HEADER_SIZE];
|
||||
dest->crc = (packet_crc_t *)&dest->data[AC_HEADER_SIZE + dest->header->body_length];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// устанавливает состояние конечного автомата
|
||||
@@ -777,7 +784,6 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
if (this->peek() == AC_PACKET_START_BYTE) {
|
||||
// если во входящий пакет что-то уже загружено, значит это какие-то ошибочные данные или неизвестные пакеты
|
||||
// надо эту инфу вывалить в лог
|
||||
@@ -1579,6 +1585,27 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
// бинарный сенсор, отображающий состояние дисплея
|
||||
esphome::binary_sensor::BinarySensor *sensor_display_ = nullptr;
|
||||
|
||||
|
||||
// загружает на выполнение последовательность команд на включение/выключение табло с температурой
|
||||
bool _displaySequence(ac_display dsp = AC_DISPLAY_ON){
|
||||
// нет смысла в последовательности, если нет коннекта с кондиционером
|
||||
if (!get_has_connection()) {
|
||||
_debugMsg(F("displaySequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
|
||||
return false;
|
||||
}
|
||||
if (dsp == AC_DISPLAY_UNTOUCHED) return false; // выходим, чтобы не тратить время
|
||||
|
||||
// формируем команду
|
||||
ac_command_t cmd;
|
||||
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
|
||||
cmd.display = dsp;
|
||||
// добавляем команду в последовательность
|
||||
if (!commandSequence(&cmd)) return false;
|
||||
|
||||
_debugMsg(F("displaySequence: loaded (display = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, dsp);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
// инициализация объекта
|
||||
void initAC(esphome::uart::UARTComponent *parent = nullptr){
|
||||
@@ -1858,11 +1885,19 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
if (sensor_display_ != nullptr)
|
||||
switch (_current_ac_state.display) {
|
||||
case AC_DISPLAY_ON:
|
||||
if (this->get_display_inverted()) {
|
||||
sensor_display_->publish_state(false);
|
||||
} else {
|
||||
sensor_display_->publish_state(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case AC_DISPLAY_OFF:
|
||||
if (this->get_display_inverted()) {
|
||||
sensor_display_->publish_state(true);
|
||||
} else {
|
||||
sensor_display_->publish_state(false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1877,6 +1912,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
ESP_LOGCONFIG(Constants::TAG, " [x] Firmware version: %s", Constants::AC_FIRMWARE_VERSION.c_str());
|
||||
ESP_LOGCONFIG(Constants::TAG, " [x] Period: %dms", this->get_period());
|
||||
ESP_LOGCONFIG(Constants::TAG, " [x] Show action: %s", this->get_show_action() ? "true" : "false");
|
||||
ESP_LOGCONFIG(Constants::TAG, " [x] Display inverted: %s", this->get_display_inverted() ? "true" : "false");
|
||||
if ((this->sensor_indoor_temperature_) != nullptr) {
|
||||
ESP_LOGCONFIG(Constants::TAG, "%s%s '%s'", " ", LOG_STR_LITERAL("Indoor Temperature"), (this->sensor_indoor_temperature_)->get_name().c_str());
|
||||
if (!(this->sensor_indoor_temperature_)->get_device_class().empty()) {
|
||||
@@ -2259,12 +2295,12 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
|
||||
/*************************************** getBigInfo request ***********************************************/
|
||||
if (!_addSequenceFuncStep(&AirCon::sq_requestBigStatus)) {
|
||||
_debugMsg(F("getStatusSmall: getBigInfo request sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
_debugMsg(F("getStatusBig: getBigInfo request sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
return false;
|
||||
}
|
||||
/*************************************** getBigInfo control ***********************************************/
|
||||
if (!_addSequenceFuncStep(&AirCon::sq_controlBigStatus)) {
|
||||
_debugMsg(F("getStatusSmall: getBigInfo control sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
_debugMsg(F("getStatusBig: getBigInfo control sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
return false;
|
||||
}
|
||||
/**************************************************************************************/
|
||||
@@ -2345,12 +2381,12 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
|
||||
/*************************************** set params request ***********************************************/
|
||||
if (!_addSequenceFuncStep(&AirCon::sq_requestDoCommand, cmd)) {
|
||||
_debugMsg(F("getStatusSmall: getBigInfo request sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
_debugMsg(F("commandSequence: getBigInfo request sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
return false;
|
||||
}
|
||||
/*************************************** set params control ***********************************************/
|
||||
if (!_addSequenceFuncStep(&AirCon::sq_controlDoCommand)) {
|
||||
_debugMsg(F("getStatusSmall: getBigInfo control sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
_debugMsg(F("commandSequence: getBigInfo control sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||
return false;
|
||||
}
|
||||
/**************************************************************************************/
|
||||
@@ -2385,40 +2421,29 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
||||
return true;
|
||||
}
|
||||
|
||||
// загружает на выполнение последовательность команд на включение/выключение табло с температурой
|
||||
bool displaySequence(ac_display dsp = AC_DISPLAY_ON){
|
||||
// нет смысла в последовательности, если нет коннекта с кондиционером
|
||||
if (!get_has_connection()) {
|
||||
_debugMsg(F("displaySequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
|
||||
return false;
|
||||
}
|
||||
if (dsp == AC_DISPLAY_UNTOUCHED) return false; // выходим, чтобы не тратить время
|
||||
|
||||
// формируем команду
|
||||
ac_command_t cmd;
|
||||
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
|
||||
cmd.display = dsp;
|
||||
// добавляем команду в последовательность
|
||||
if (!commandSequence(&cmd)) return false;
|
||||
|
||||
_debugMsg(F("displaySequence: loaded (display = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, dsp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// выключает экран
|
||||
bool displayOffSequence(){
|
||||
return displaySequence(AC_DISPLAY_OFF);
|
||||
ac_display dsp = AC_DISPLAY_OFF;
|
||||
if (this->get_display_inverted()) dsp = AC_DISPLAY_ON;
|
||||
return _displaySequence(dsp);
|
||||
}
|
||||
|
||||
// включает экран
|
||||
bool displayOnSequence(){
|
||||
return displaySequence(AC_DISPLAY_ON);
|
||||
ac_display dsp = AC_DISPLAY_ON;
|
||||
if (this->get_display_inverted()) dsp = AC_DISPLAY_OFF;
|
||||
return _displaySequence(dsp);
|
||||
}
|
||||
|
||||
void set_period(uint32_t ms) { this->_update_period = ms; };
|
||||
uint32_t get_period() { return this->_update_period; };
|
||||
void set_show_action(bool show_action) { this->_show_action = show_action; };
|
||||
bool get_show_action() {return this->_show_action; };
|
||||
void set_period(uint32_t ms) { this->_update_period = ms; }
|
||||
uint32_t get_period() { return this->_update_period; }
|
||||
|
||||
void set_show_action(bool show_action) { this->_show_action = show_action; }
|
||||
bool get_show_action() { return this->_show_action; }
|
||||
|
||||
void set_display_inverted(bool display_inverted) { this->_display_inverted = display_inverted; }
|
||||
bool get_display_inverted() { return this->_display_inverted; }
|
||||
|
||||
void set_supported_modes(const std::set<ClimateMode> &modes) { this->_supported_modes = modes; }
|
||||
void set_supported_swing_modes(const std::set<ClimateSwingMode> &modes) { this->_supported_swing_modes = modes; }
|
||||
void set_supported_presets(const std::set<ClimatePreset> &presets) { this->_supported_presets = presets; }
|
||||
|
||||
@@ -35,6 +35,7 @@ CONF_SHOW_ACTION = 'show_action'
|
||||
CONF_INDOOR_TEMPERATURE = 'indoor_temperature'
|
||||
CONF_DISPLAY_STATE = 'display_state'
|
||||
|
||||
CONF_DISPLAY_INVERTED = 'display_inverted'
|
||||
ICON_DISPLAY = "mdi:numeric"
|
||||
|
||||
aux_ac_ns = cg.esphome_ns.namespace("aux_ac")
|
||||
@@ -89,6 +90,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.GenerateID(): cv.declare_id(AirCon),
|
||||
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_INDOOR_TEMPERATURE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_CELSIUS,
|
||||
icon=ICON_THERMOMETER,
|
||||
@@ -141,6 +143,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]))
|
||||
if CONF_SUPPORTED_MODES in config:
|
||||
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
|
||||
if CONF_SUPPORTED_SWING_MODES in config:
|
||||
|
||||
@@ -63,6 +63,7 @@ climate:
|
||||
uart_id: ac_uart_bus
|
||||
period: 7s
|
||||
show_action: true
|
||||
display_inverted: true
|
||||
indoor_temperature:
|
||||
name: ${upper_devicename} AC Indoor Temperature
|
||||
id: ${devicename}_indoor_temp
|
||||
|
||||
@@ -56,6 +56,7 @@ climate:
|
||||
uart_id: ac_uart_bus
|
||||
period: 7s # период опроса состояния сплита, по дефолту 7 сек
|
||||
show_action: true # надо ли показывать текущий режим работы: при HEAT_COOL mode сплит может греть (HEAT), охлаждать (COOL) или бездействовать (IDLE)
|
||||
display_inverted: true # как отрабатывать вкл/выкл дисплея: у Rovex "1" выключает дисплей, у многих других "1" дисплей включает
|
||||
indoor_temperature: # сенсор, показывающий температуру воздуха на внутреннем блоке кондиционера; имеет все те же параметры, как и любой сенсор ESPHome
|
||||
name: AC Indoor Temperature
|
||||
id: ac_indoor_temp
|
||||
|
||||
Reference in New Issue
Block a user