Fix status parsing and power flag handling

This commit is contained in:
christoph
2025-12-17 15:13:38 +01:00
parent f185c1fe6c
commit 3f9c49d28f
2 changed files with 46 additions and 33 deletions

View File

@@ -14,6 +14,8 @@
namespace esphome{ namespace esphome{
namespace tclac{ namespace tclac{
constexpr uint8_t TCL_FRAME_TYPE_STATUS = 0x04;
constexpr size_t TCL_STATUS_FRAME_MIN_SIZE = 40;
ClimateTraits tclacClimate::traits() { ClimateTraits tclacClimate::traits() {
auto traits = climate::ClimateTraits(); auto traits = climate::ClimateTraits();
@@ -51,17 +53,27 @@ void tclacClimate::setup() {
} }
void tclacClimate::loop() { void tclacClimate::loop() {
// Если в буфере UART что-то есть, то читаем это что-то
if (esphome::uart::UARTDevice::available() > 0) { if (esphome::uart::UARTDevice::available() > 0) {
dataShow(0, true); dataShow(0, true);
dataRX[0] = esphome::uart::UARTDevice::read(); size_t skipped = 0;
// Если принятый байт- не заголовок (0xBB), то просто покидаем цикл bool header_found = false;
if (dataRX[0] != 0xBB) { while (esphome::uart::UARTDevice::available() > 0) {
ESP_LOGD("TCL", "Wrong byte"); uint8_t byte = esphome::uart::UARTDevice::read();
if (byte == 0xBB) {
dataRX[0] = byte;
header_found = true;
break;
}
skipped += 1;
}
if (!header_found) {
if (skipped > 0)
ESP_LOGV("TCL", "Skipped %u byte(s) waiting for header", (unsigned) skipped);
dataShow(0,0); dataShow(0,0);
return; return;
} }
// А вот если совпал заголовок (0xBB), то начинаем чтение по цепочке еще 4 байт if (skipped > 0)
ESP_LOGV("TCL", "Resynced after skipping %u byte(s)", (unsigned) skipped);
delay(5); delay(5);
dataRX[1] = esphome::uart::UARTDevice::read(); dataRX[1] = esphome::uart::UARTDevice::read();
delay(5); delay(5);
@@ -70,32 +82,30 @@ void tclacClimate::loop() {
dataRX[3] = esphome::uart::UARTDevice::read(); dataRX[3] = esphome::uart::UARTDevice::read();
delay(5); delay(5);
dataRX[4] = esphome::uart::UARTDevice::read(); dataRX[4] = esphome::uart::UARTDevice::read();
size_t payload_with_checksum = static_cast<size_t>(dataRX[4]) + 1;
//auto raw = getHex(dataRX, 5); size_t frame_size = payload_with_checksum + 5;
if (frame_size > sizeof(dataRX)) {
//ESP_LOGD("TCL", "first 5 byte : %s ", raw.c_str()); ESP_LOGW("TCL", "Frame size %u exceeds buffer", (unsigned) frame_size);
tclacClimate::dataShow(0,0);
// Из первы<D0B2> return;
5 байт нам нужен пятый- он содержит длину сообщения }
esphome::uart::UARTDevice::read_array(dataRX+5, dataRX[4]+1); esphome::uart::UARTDevice::read_array(dataRX + 5, payload_with_checksum);
uint8_t check = getChecksum(dataRX, frame_size);
uint8_t check = getChecksum(dataRX, sizeof(dataRX)); if (check != dataRX[frame_size - 1]) {
//raw = getHex(dataRX, sizeof(dataRX));
//ESP_LOGD("TCL", "RX full : %s ", raw.c_str());
// Проверяем контрольную сумму
if (check != dataRX[60]) {
ESP_LOGD("TCL", "Invalid checksum %x", check); ESP_LOGD("TCL", "Invalid checksum %x", check);
tclacClimate::dataShow(0,0); tclacClimate::dataShow(0,0);
return; return;
} else {
//ESP_LOGD("TCL", "checksum OK %x", check);
} }
tclacClimate::dataShow(0,0); tclacClimate::dataShow(0,0);
// Прочитав все из буфера приступаем к разбору данны<D0BD> uint8_t frame_type = dataRX[3];
if (frame_type != TCL_FRAME_TYPE_STATUS) {
ESP_LOGV("TCL", "Ignoring frame type 0x%02X", frame_type);
return;
}
if (frame_size < TCL_STATUS_FRAME_MIN_SIZE) {
ESP_LOGV("TCL", "Ignoring short status frame (%u bytes)", (unsigned) frame_size);
return;
}
tclacClimate::readData(); tclacClimate::readData();
} }
} }
@@ -115,7 +125,8 @@ void tclacClimate::readData() {
//ESP_LOGD("TCL", "TEMP: %f ", current_temperature); //ESP_LOGD("TCL", "TEMP: %f ", current_temperature);
if (dataRX[MODE_POS] & ( 1 << 4)) { bool device_is_on = (dataRX[MODE_POS] & MODE_STATUS_POWER_FLAG) != 0;
if (device_is_on) {
// Если кондиционер включен, то разбираем данные для отображения // Если кондиционер включен, то разбираем данные для отображения
// ESP_LOGD("TCL", "AC is on"); // ESP_LOGD("TCL", "AC is on");
uint8_t modeswitch = MODE_MASK & dataRX[MODE_POS]; uint8_t modeswitch = MODE_MASK & dataRX[MODE_POS];
@@ -308,23 +319,23 @@ void tclacClimate::takeControl() {
dataTX[8] += 0b00000000; dataTX[8] += 0b00000000;
break; break;
case climate::CLIMATE_MODE_AUTO: case climate::CLIMATE_MODE_AUTO:
dataTX[7] += 0b00000100; dataTX[7] += MODE_COMMAND_POWER_FLAG;
dataTX[8] += 0b00001000; dataTX[8] += 0b00001000;
break; break;
case climate::CLIMATE_MODE_COOL: case climate::CLIMATE_MODE_COOL:
dataTX[7] += 0b00000100; dataTX[7] += MODE_COMMAND_POWER_FLAG;
dataTX[8] += 0b00000011; dataTX[8] += 0b00000011;
break; break;
case climate::CLIMATE_MODE_DRY: case climate::CLIMATE_MODE_DRY:
dataTX[7] += 0b00000100; dataTX[7] += MODE_COMMAND_POWER_FLAG;
dataTX[8] += 0b00000010; dataTX[8] += 0b00000010;
break; break;
case climate::CLIMATE_MODE_FAN_ONLY: case climate::CLIMATE_MODE_FAN_ONLY:
dataTX[7] += 0b00000100; dataTX[7] += MODE_COMMAND_POWER_FLAG;
dataTX[8] += 0b00000111; dataTX[8] += 0b00000111;
break; break;
case climate::CLIMATE_MODE_HEAT: case climate::CLIMATE_MODE_HEAT:
dataTX[7] += 0b00000100; dataTX[7] += MODE_COMMAND_POWER_FLAG;
dataTX[8] += 0b00000001; dataTX[8] += 0b00000001;
break; break;
} }

View File

@@ -28,6 +28,8 @@ using byte = uint8_t;
#define MODE_POS 7 #define MODE_POS 7
#define MODE_MASK 0b00111111 #define MODE_MASK 0b00111111
#define MODE_STATUS_POWER_FLAG 0b00010000
#define MODE_COMMAND_POWER_FLAG 0b00000100
#define MODE_AUTO 0b00110101 #define MODE_AUTO 0b00110101
#define MODE_COOL 0b00110001 #define MODE_COOL 0b00110001