formatting + horizontal louvers patch

This commit is contained in:
GrKoR
2022-07-14 18:54:53 +03:00
parent 1e017530ac
commit 4655902ca2

View File

@@ -415,9 +415,12 @@ enum ac_louver_V : uint8_t {
// Горизонтальные жалюзи. В протоколе зашита возможность двигать ими по всякому, но должна быть такая возможность на уровне железа.
// горизонтальные жалюзи выставлять в определенное положение не вышло, протестировано.
#define AC_LOUVERH_MASK 0b11100000
enum ac_louver_H : uint8_t { AC_LOUVERH_SWING_LEFTRIGHT = 0x00,
AC_LOUVERH_OFF = 0xE0,
AC_LOUVERH_UNTOUCHED = 0xFF };
enum ac_louver_H : uint8_t {
AC_LOUVERH_SWING_LEFTRIGHT = 0x00,
AC_LOUVERH_OFF_AUX = 0x20, // 0b00100000
AC_LOUVERH_OFF_ALTERNATIVE = 0xE0, // 0b11100000 - по коду везде кроме проверок использую его, так как у него все три бита в 1
AC_LOUVERH_UNTOUCHED = 0xFF
};
struct ac_louver {
ac_louver_H louver_h;
@@ -547,6 +550,16 @@ struct ac_command_t {
typedef ac_command_t ac_state_t; // текущее состояние параметров кондея можно хранить в таком же формате, как и комманды
// Структура для хранения последних полученных от сплита информационных пакетов в сыром виде
// Нужно до тех пор, пока весь функционал не разберем в структуру статуса.
// Используем для проверки реакции сплита на команды (так отлавливаем разные версии протокола общения wifi-модуля с кондиционером)
// Каждый пакет имеет поле msec. Если оно равно нулю, значит пакеты еще не принимались. По этому же полю можно смотреть, как давно
// принималась информация от кондиционера, делать вывод об отвале и рапортовать об ошибке.
struct ac_last_raw_data {
packet_t last_small_info_packet;
packet_t last_big_info_packet;
};
//****************************************************************************************************************************************************
//************************************************ КОНЕЦ ПАРАМЕТРОВ РАБОТЫ КОНДИЦИОНЕРА **************************************************************
//****************************************************************************************************************************************************
@@ -697,6 +710,9 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
// пакет для тестирования всякой фигни
packet_t _outTestPacket;
// сырые данные последних полученных большого и маленького информационных пакетов
ac_last_raw_data _last_raw_data;
// последовательность пакетов текущий шаг в последовательности
sequence_item_t _sequence[AC_SEQUENCE_MAX_LEN];
uint8_t _sequence_current_step;
@@ -891,6 +907,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
cmd->temp_outbound = 0;
cmd->temp_compressor = 0;
cmd->realFanSpeed = AC_REAL_FAN_UNTOUCHED;
cmd->invertor_power = 0;
cmd->defrost = false;
};
// очистка буфера размером AC_BUFFER_SIZE
@@ -982,7 +1000,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
// но потом понял, что у нас пакеты уходят не только когда надо отвечать, но и мы можем быть инициаторами
// поэтому вызов отправки тут пригодится
if (_outPacket.msec > 0) _setStateMachineState(ACSM_SENDING_PACKET);
// иначе просто выходим
// больше дел нет - выходим
return;
};
@@ -1143,8 +1161,16 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
}
case AC_PTYPE_INFO: { // информационный пакет
// смотрим тип поступившего пакета по второму байту тела
_debugMsg(F("Parser: status packet received"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
// смотрим тип поступившего пакета по второму байту тела
// но вначале проверяем, что такое тело вообще есть
if ((_inPacket.body == nullptr) || (_inPacket.bytesLoaded < AC_HEADER_SIZE + 4) || (_inPacket.header->body_length < 2)) {
_debugMsg(F("Parser: packet type=0x07 without body. Error!"), ESPHOME_LOG_LEVEL_WARN, __LINE__);
_clearInPacket();
_setStateMachineState(ACSM_IDLE);
break;
}
// теперь можно проверять второй байт тела пакета
switch (_inPacket.body[1]) {
case AC_CMD_STATUS_SMALL: { // маленький пакет статуса кондиционера
_debugMsg(F("Parser: status packet type = small"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
@@ -1554,7 +1580,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
pack->header->start_byte = AC_PACKET_START_BYTE;
pack->header->wifi = AC_PACKET_ANSWER; // для исходящего пакета ставим признак ответа
pack->header->packet_type = AC_PTYPE_CMD;
pack->header->body_length = 15; // тело команды 15 байт, как у Small status
pack->header->body_length = 0x0F; // тело команды 15 (0x0F) байт, как у Small status
pack->body = &(pack->data[AC_HEADER_SIZE]);
pack->body[0] = AC_CMD_SET_PARAMS; // устанавливаем параметры
pack->body[1] = 0x01; // он всегда 0x01
@@ -1616,6 +1642,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
if (cmd->power != AC_POWER_UNTOUCHED) {
pack->body[10] = (pack->body[10] & ~AC_POWER_MASK) | cmd->power;
}
// просушка
if (cmd->clean != AC_CLEAN_UNTOUCHED) {
pack->body[10] = (pack->body[10] & ~AC_CLEAN_MASK) | cmd->clean;
}
@@ -1682,8 +1710,13 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
relevant = (relevant && (_inPacket.body[0] == 0x01));
relevant = (relevant && (_inPacket.body[1] == AC_CMD_STATUS_SMALL));
// если пакет подходит, значит можно переходить к следующему шагу
// если пакет подходит...
if (relevant) {
// ...значит можно переходить к следующему шагу
// так как пакет корректный, то его можно скопировать в последние полученные пакеты
_copyPacket(&_last_raw_data.last_small_info_packet, &_inPacket);
// отчитываемся в лог и переходим к следующему шагу
_debugMsg(F("Sequence [step %u]: correct small status packet received"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _sequence_current_step);
_sequence_current_step++;
} else {
@@ -1734,8 +1767,13 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
relevant = (relevant && (_inPacket.body[0] == 0x01));
relevant = (relevant && (_inPacket.body[1] == AC_CMD_STATUS_BIG));
// если пакет подходит, значит можно переходить к следующему шагу
// если пакет подходит...
if (relevant) {
// ...значит можно переходить к следующему шагу
// так как пакет корректный, то его можно скопировать в последние полученные пакеты
_copyPacket(&_last_raw_data.last_big_info_packet, &_inPacket);
// отчитываемся в лог и переходим к следующему шагу
_debugMsg(F("Sequence [step %u]: correct big status packet received"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _sequence_current_step);
_sequence_current_step++;
} else {
@@ -1912,6 +1950,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
_clearInPacket();
_clearOutPacket();
_clearPacket(&_outTestPacket);
_clearPacket(&_last_raw_data.last_big_info_packet);
_clearPacket(&_last_raw_data.last_small_info_packet);
_setStateMachineState(ACSM_IDLE);
_ac_serial = parent;
@@ -1961,9 +2001,9 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
void stateChanged() {
_debugMsg(F("State changed, let's publish it."), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
// TODO: сейчас экшины рассчётные и могут не отражать реального положения дел.
// В протоколе расшифрованы байты, позволяющие выводить реальный экшн. Требуется исправить.
if (_is_invertor) { // анализ режима для инвертора, точнее потому что использует показания мощности инвертора
// сейчас экшины рассчётные и могут не отражать реального положения дел, но других вариантов не придумалось
if (_is_invertor) {
// анализ режима для инвертора точнее потому, что использует показания мощности инвертора
static uint32_t timerInv = 0;
if (_current_ac_state.invertor_power == 0) { // инвертор выключен
timerInv = millis();
@@ -2010,7 +2050,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
this->action = climate::CLIMATE_ACTION_FAN; // другие режимы - вентиляция
}
}
} else {
} else { // if(_is_invertor)
// для on-off сплита рассчет экшена упрощен
if (_current_ac_state.realFanSpeed == AC_REAL_FAN_OFF &&
_current_ac_state.power == AC_POWER_OFF) {
this->action = climate::CLIMATE_ACTION_OFF; // значит кондей не работает
@@ -2018,7 +2059,6 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
int16_t delta_temp = _current_ac_state.temp_ambient - _current_ac_state.temp_inbound; // разность температуры между комнатной и входящей
if (delta_temp > 0 && delta_temp < 2 &&
(_current_ac_state.realFanSpeed == AC_REAL_FAN_OFF ||
_current_ac_state.realFanSpeed == AC_REAL_FAN_MUTE ||
_current_ac_state.realFanSpeed == AC_REAL_FAN_MUTE)) {
this->action = climate::CLIMATE_ACTION_DRYING; // ОСУШЕНИЕ
} else if (_current_ac_state.realFanSpeed != AC_REAL_FAN_OFF &&
@@ -2214,7 +2254,15 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
if (_current_ac_state.power == AC_POWER_ON) {
if (_current_ac_state.louver.louver_h == AC_LOUVERH_SWING_LEFTRIGHT && _current_ac_state.louver.louver_v == AC_LOUVERV_OFF) {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
} else if (_current_ac_state.louver.louver_h == AC_LOUVERH_OFF && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN) {
} else if (_current_ac_state.louver.louver_h == AC_LOUVERH_OFF_AUX && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN) {
// TODO: КОСТЫЛЬ!
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
} else if (_current_ac_state.louver.louver_h == AC_LOUVERH_OFF_ALTERNATIVE && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN) {
// TODO: КОСТЫЛЬ!
// временно сделал так. Сделать нормально - это надо подумать.
// На AUX и многих других марках выключенный режим горизонтальных жалюзи равен 0x20, а на ROVEX и Royal Clima 0xE0
// Из-за этого происходил сброс на OFF во фронтенде Home Assistant. Пришлось городить это.
// Надо как-то изящнее решить эту историю
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
} else if (_current_ac_state.louver.louver_h == AC_LOUVERH_SWING_LEFTRIGHT && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN) {
this->swing_mode = climate::CLIMATE_SWING_BOTH;
@@ -2623,7 +2671,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
// But the ROVEX IR-remote does not provide this features. Therefore this features haven't been tested.
// May be suitable for other models of AUX-based ACs.
case climate::CLIMATE_SWING_OFF:
cmd.louver.louver_h = AC_LOUVERH_OFF;
cmd.louver.louver_h = AC_LOUVERH_OFF_ALTERNATIVE;
cmd.louver.louver_v = AC_LOUVERV_OFF;
hasCommand = true;
this->swing_mode = swingmode;
@@ -2637,7 +2685,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
break;
case climate::CLIMATE_SWING_VERTICAL:
cmd.louver.louver_h = AC_LOUVERH_OFF;
cmd.louver.louver_h = AC_LOUVERH_OFF_ALTERNATIVE;
cmd.louver.louver_v = AC_LOUVERV_SWING_UPDOWN;
hasCommand = true;
this->swing_mode = swingmode;