From 7719179dcdc27087b75fbb10520fb8764c75dbf5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 20 Oct 2026 02:44:13 -1000 Subject: [PATCH] [tcl112][zhlt01][heatpumpir][fujitsu_general] Send and read IR frame bytes with the remote_base helpers (#21168) --- .../fujitsu_general/fujitsu_general.cpp | 42 +++++-------------- .../heatpumpir/receiver_mitsubishi_heavy.cpp | 17 ++------ esphome/components/tcl112/tcl112.cpp | 28 ++++--------- esphome/components/zhlt01/zhlt01.cpp | 33 +++++---------- esphome/components/zhlt01/zhlt01.h | 4 +- 5 files changed, 34 insertions(+), 90 deletions(-) diff --git a/esphome/components/fujitsu_general/fujitsu_general.cpp b/esphome/components/fujitsu_general/fujitsu_general.cpp index af411d133a8..559e6ae831a 100644 --- a/esphome/components/fujitsu_general/fujitsu_general.cpp +++ b/esphome/components/fujitsu_general/fujitsu_general.cpp @@ -66,9 +66,8 @@ constexpr uint8_t FUJITSU_GENERAL_FAN_SILENT = 0x04; constexpr uint16_t FUJITSU_GENERAL_HEADER_MARK = 3300; constexpr uint16_t FUJITSU_GENERAL_HEADER_SPACE = 1600; -constexpr uint16_t FUJITSU_GENERAL_BIT_MARK = 420; -constexpr uint16_t FUJITSU_GENERAL_ONE_SPACE = 1200; -constexpr uint16_t FUJITSU_GENERAL_ZERO_SPACE = 420; +static constexpr remote_base::BitTimings FUJITSU_GENERAL_BIT_TIMINGS{ + .bit_mark = 420, .one_space = 1200, .zero_space = 420}; constexpr uint16_t FUJITSU_GENERAL_TRL_MARK = 420; constexpr uint16_t FUJITSU_GENERAL_TRL_SPACE = 8000; @@ -207,14 +206,7 @@ void FujitsuGeneralClimate::transmit_(uint8_t const *message, uint8_t length) { data->space(FUJITSU_GENERAL_HEADER_SPACE); // Data - for (uint8_t i = 0; i < length; ++i) { - const uint8_t byte = message[i]; - for (uint8_t mask = 0b00000001; mask > 0; mask <<= 1) { // write from right to left - data->mark(FUJITSU_GENERAL_BIT_MARK); - bool bit = byte & mask; - data->space(bit ? FUJITSU_GENERAL_ONE_SPACE : FUJITSU_GENERAL_ZERO_SPACE); - } - } + data->item_bytes(message, length); // Footer data->mark(FUJITSU_GENERAL_TRL_MARK); @@ -284,19 +276,12 @@ bool FujitsuGeneralClimate::on_receive(remote_base::RemoteReceiveData data) { return false; } - uint8_t recv_message[FUJITSU_GENERAL_STATE_MESSAGE_LENGTH] = {0}; + uint8_t recv_message[FUJITSU_GENERAL_STATE_MESSAGE_LENGTH]; // Read header - for (uint8_t byte = 0; byte < FUJITSU_GENERAL_COMMON_LENGTH; ++byte) { - // Read bit - for (uint8_t bit = 0; bit < 8; ++bit) { - if (data.expect_item(FUJITSU_GENERAL_BIT_MARK, FUJITSU_GENERAL_ONE_SPACE)) { - recv_message[byte] |= 1 << bit; // read from right to left - } else if (!data.expect_item(FUJITSU_GENERAL_BIT_MARK, FUJITSU_GENERAL_ZERO_SPACE)) { - ESP_LOGV(TAG, "Byte %d bit %d fail", byte, bit); - return false; - } - } + if (!data.expect_bytes(recv_message, FUJITSU_GENERAL_COMMON_LENGTH)) { + ESP_LOGV(TAG, "Header bytes fail"); + return false; } const uint8_t recv_message_type = recv_message[FUJITSU_GENERAL_MESSAGE_TYPE_BYTE]; @@ -319,15 +304,10 @@ bool FujitsuGeneralClimate::on_receive(remote_base::RemoteReceiveData data) { } // Read message body - for (uint8_t byte = FUJITSU_GENERAL_COMMON_LENGTH; byte < recv_message_length; ++byte) { - for (uint8_t bit = 0; bit < 8; ++bit) { - if (data.expect_item(FUJITSU_GENERAL_BIT_MARK, FUJITSU_GENERAL_ONE_SPACE)) { - recv_message[byte] |= 1 << bit; // read from right to left - } else if (!data.expect_item(FUJITSU_GENERAL_BIT_MARK, FUJITSU_GENERAL_ZERO_SPACE)) { - ESP_LOGV(TAG, "Byte %d bit %d fail", byte, bit); - return false; - } - } + if (!data.expect_bytes(recv_message + FUJITSU_GENERAL_COMMON_LENGTH, + recv_message_length - FUJITSU_GENERAL_COMMON_LENGTH)) { + ESP_LOGV(TAG, "Body bytes fail"); + return false; } for (uint8_t byte = 0; byte < recv_message_length; ++byte) { diff --git a/esphome/components/heatpumpir/receiver_mitsubishi_heavy.cpp b/esphome/components/heatpumpir/receiver_mitsubishi_heavy.cpp index 004eb46c007..68d5ecfaca2 100644 --- a/esphome/components/heatpumpir/receiver_mitsubishi_heavy.cpp +++ b/esphome/components/heatpumpir/receiver_mitsubishi_heavy.cpp @@ -15,24 +15,15 @@ static constexpr uint8_t MODE_MASK = 0x07; static constexpr uint8_t TEMP_MASK = 0x0F; static constexpr uint8_t TEMPERATURE_BASE = 17; static constexpr uint8_t TEMPERATURE_SHIFT = 4; +static constexpr remote_base::BitTimings MITSUBISHI_HEAVY_BIT_TIMINGS{.bit_mark = MITSUBISHI_HEAVY_BIT_MARK, + .one_space = MITSUBISHI_HEAVY_ONE_SPACE, + .zero_space = MITSUBISHI_HEAVY_ZERO_SPACE}; static bool read_raw_bytes(remote_base::RemoteReceiveData &data, uint8_t frame[MITSUBISHI_HEAVY_FRAME_LENGTH]) { if (!data.expect_item(MITSUBISHI_HEAVY_HDR_MARK, MITSUBISHI_HEAVY_HDR_SPACE)) return false; - for (uint8_t i = 0; i < MITSUBISHI_HEAVY_FRAME_LENGTH; i++) { - uint8_t byte = 0; - for (uint8_t bit = 0; bit < 8; bit++) { - if (data.expect_item(MITSUBISHI_HEAVY_BIT_MARK, MITSUBISHI_HEAVY_ONE_SPACE)) { - byte |= 1 << bit; - } else if (!data.expect_item(MITSUBISHI_HEAVY_BIT_MARK, MITSUBISHI_HEAVY_ZERO_SPACE)) { - return false; - } - } - frame[i] = byte; - } - - return true; + return data.expect_bytes(frame, MITSUBISHI_HEAVY_FRAME_LENGTH); } static bool validate_prefix(const uint8_t frame[MITSUBISHI_HEAVY_FRAME_LENGTH]) { diff --git a/esphome/components/tcl112/tcl112.cpp b/esphome/components/tcl112/tcl112.cpp index 15111338b24..d1647a522b5 100644 --- a/esphome/components/tcl112/tcl112.cpp +++ b/esphome/components/tcl112/tcl112.cpp @@ -27,8 +27,8 @@ const uint8_t TCL112_HALF_DEGREE = 0b00100000; const uint16_t TCL112_HEADER_MARK = 3100; const uint16_t TCL112_HEADER_SPACE = 1650; const uint16_t TCL112_BIT_MARK = 500; -const uint16_t TCL112_ONE_SPACE = 1100; -const uint16_t TCL112_ZERO_SPACE = 350; +static constexpr remote_base::BitTimings TCL112_BIT_TIMINGS{ + .bit_mark = TCL112_BIT_MARK, .one_space = 1100, .zero_space = 350}; const uint32_t TCL112_GAP = TCL112_HEADER_SPACE; void Tcl112Climate::transmit_state() { @@ -128,13 +128,7 @@ void Tcl112Climate::transmit_state() { data->mark(TCL112_HEADER_MARK); data->space(TCL112_HEADER_SPACE); // Data - for (uint8_t i : remote_state) { - for (uint8_t j = 0; j < 8; j++) { - data->mark(TCL112_BIT_MARK); - bool bit = i & (1 << j); - data->space(bit ? TCL112_ONE_SPACE : TCL112_ZERO_SPACE); - } - } + data->item_bytes(remote_state, TCL112_STATE_LENGTH); // Footer data->mark(TCL112_BIT_MARK); data->space(TCL112_GAP); @@ -149,18 +143,10 @@ bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) { return false; } - uint8_t remote_state[TCL112_STATE_LENGTH] = {0}; - // Read all bytes. - for (int i = 0; i < TCL112_STATE_LENGTH; i++) { - // Read bit - for (int j = 0; j < 8; j++) { - if (data.expect_item(TCL112_BIT_MARK, TCL112_ONE_SPACE)) { - remote_state[i] |= 1 << j; - } else if (!data.expect_item(TCL112_BIT_MARK, TCL112_ZERO_SPACE)) { - ESP_LOGVV(TAG, "Byte %d bit %d fail", i, j); - return false; - } - } + uint8_t remote_state[TCL112_STATE_LENGTH]; + if (!data.expect_bytes(remote_state, TCL112_STATE_LENGTH)) { + ESP_LOGVV(TAG, "Data fail"); + return false; } // Validate footer if (!data.expect_mark(TCL112_BIT_MARK)) { diff --git a/esphome/components/zhlt01/zhlt01.cpp b/esphome/components/zhlt01/zhlt01.cpp index afca7bf8603..15dff612ea5 100644 --- a/esphome/components/zhlt01/zhlt01.cpp +++ b/esphome/components/zhlt01/zhlt01.cpp @@ -5,8 +5,10 @@ namespace esphome::zhlt01 { ESPHOME_LOG_TAG(TAG, "zhlt01.climate"); +static constexpr uint8_t ZHLT01_MESSAGE_LENGTH = 12; + void ZHLT01Climate::transmit_state() { - uint8_t ir_message[12] = {0}; + uint8_t ir_message[ZHLT01_MESSAGE_LENGTH] = {0}; // Byte 1 : Timer ir_message[1] = 0x00; // Timer off @@ -102,7 +104,7 @@ void ZHLT01Climate::transmit_state() { ir_message[11] = 0xD5; // Set checksum bytes - for (int i = 0; i < 12; i += 2) { + for (int i = 0; i < ZHLT01_MESSAGE_LENGTH; i += 2) { ir_message[i] = ~ir_message[i + 1]; } @@ -117,13 +119,7 @@ void ZHLT01Climate::transmit_state() { data->space(AC1_HDR_SPACE); // Data - for (uint8_t i : ir_message) { - for (uint8_t j = 0; j < 8; j++) { - data->mark(AC1_BIT_MARK); - bool bit = i & (1 << j); - data->space(bit ? AC1_ONE_SPACE : AC1_ZERO_SPACE); - } - } + data->item_bytes(ir_message, sizeof(ir_message)); // Footer data->mark(AC1_BIT_MARK); @@ -140,19 +136,10 @@ bool ZHLT01Climate::on_receive(remote_base::RemoteReceiveData data) { } // Decode IR message - uint8_t ir_message[12] = {0}; - // Read all bytes - for (int i = 0; i < 12; i++) { - // Read bit - for (int j = 0; j < 8; j++) { - if (data.expect_item(AC1_BIT_MARK, AC1_ONE_SPACE)) { - ir_message[i] |= 1 << j; - } else if (!data.expect_item(AC1_BIT_MARK, AC1_ZERO_SPACE)) { - ESP_LOGV(TAG, "Byte %d bit %d fail", i, j); - return false; - } - } - ESP_LOGVV(TAG, "Byte %d %02X", i, ir_message[i]); + uint8_t ir_message[ZHLT01_MESSAGE_LENGTH]; + if (!data.expect_bytes(ir_message, sizeof(ir_message))) { + ESP_LOGV(TAG, "Data fail"); + return false; } // Validate footer @@ -162,7 +149,7 @@ bool ZHLT01Climate::on_receive(remote_base::RemoteReceiveData data) { } // Validate checksum - for (int i = 0; i < 12; i += 2) { + for (int i = 0; i < ZHLT01_MESSAGE_LENGTH; i += 2) { if (ir_message[i] != (uint8_t) (~ir_message[i + 1])) { ESP_LOGV(TAG, "Byte %d checksum incorrect (%02X != %02X)", i, ir_message[i], (uint8_t) (~ir_message[i + 1])); return false; diff --git a/esphome/components/zhlt01/zhlt01.h b/esphome/components/zhlt01/zhlt01.h index dba9ca8f3da..2e9e999497b 100644 --- a/esphome/components/zhlt01/zhlt01.h +++ b/esphome/components/zhlt01/zhlt01.h @@ -100,8 +100,8 @@ namespace esphome::zhlt01 { static const uint32_t AC1_HDR_MARK = 6100; static const uint32_t AC1_HDR_SPACE = 7400; static const uint32_t AC1_BIT_MARK = 500; -static const uint32_t AC1_ZERO_SPACE = 600; -static const uint32_t AC1_ONE_SPACE = 1800; +static constexpr remote_base::BitTimings AC1_BIT_TIMINGS{ + .bit_mark = AC1_BIT_MARK, .one_space = 1800, .zero_space = 600}; /******************************************************************************** *