mirror of
https://github.com/esphome/esphome.git
synced 2026-10-21 13:34:12 +00:00
[airton][ballu][delonghi][hitachi_ac424][mitsubishi] Send and read IR frame bytes with the remote_base helpers (#21169)
This commit is contained in:
@@ -136,13 +136,7 @@ void AirtonClimate::transmit_state() {
|
||||
data->set_carrier_frequency(AIRTON_IR_FREQUENCY);
|
||||
data->mark(AIRTON_HEADER_MARK);
|
||||
data->space(AIRTON_HEADER_SPACE);
|
||||
for (uint8_t payload_byte : remote_state) {
|
||||
for (uint8_t payload_bit_cursor = 0; payload_bit_cursor < 8; payload_bit_cursor++) {
|
||||
data->mark(AIRTON_BIT_MARK);
|
||||
bool bit = payload_byte & (1 << payload_bit_cursor);
|
||||
data->space(bit ? AIRTON_ONE_SPACE : AIRTON_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
data->item_bytes<AIRTON_BIT_TIMINGS>(remote_state, AIRTON_STATE_FRAME_SIZE);
|
||||
|
||||
data->mark(AIRTON_BIT_MARK);
|
||||
data->space(AIRTON_MESSAGE_SPACE);
|
||||
@@ -284,20 +278,14 @@ void AirtonClimate::parse_state_frame_(const uint8_t *frame) {
|
||||
}
|
||||
|
||||
bool AirtonClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
uint8_t remote_state[AIRTON_STATE_FRAME_SIZE] = {};
|
||||
uint8_t remote_state[AIRTON_STATE_FRAME_SIZE];
|
||||
if (!data.expect_item(AIRTON_HEADER_MARK, AIRTON_HEADER_SPACE)) {
|
||||
ESP_LOGV(TAG, "Wrong header encoding detected!");
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < AIRTON_STATE_FRAME_SIZE; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (data.expect_item(AIRTON_BIT_MARK, AIRTON_ONE_SPACE)) {
|
||||
remote_state[i] |= 1 << j;
|
||||
} else if (!data.expect_item(AIRTON_BIT_MARK, AIRTON_ZERO_SPACE)) {
|
||||
ESP_LOGV(TAG, "Wrong modulation encoding for: Byte %d, bit %d", i, j);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!data.expect_bytes<AIRTON_BIT_TIMINGS>(remote_state, AIRTON_STATE_FRAME_SIZE)) {
|
||||
ESP_LOGV(TAG, "Wrong modulation encoding");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (remote_state[0] != AIRTON_HEADER_BYTE0 || remote_state[1] != AIRTON_HEADER_BYTE1) {
|
||||
|
||||
@@ -36,8 +36,8 @@ static constexpr uint32_t AIRTON_IR_FREQUENCY = 38000;
|
||||
static constexpr uint32_t AIRTON_HEADER_MARK = 6630;
|
||||
static constexpr uint32_t AIRTON_HEADER_SPACE = 3350;
|
||||
static constexpr uint32_t AIRTON_BIT_MARK = 400;
|
||||
static constexpr uint32_t AIRTON_ONE_SPACE = 1260;
|
||||
static constexpr uint32_t AIRTON_ZERO_SPACE = 430;
|
||||
static constexpr remote_base::BitTimings AIRTON_BIT_TIMINGS{
|
||||
.bit_mark = AIRTON_BIT_MARK, .one_space = 1260, .zero_space = 430};
|
||||
static constexpr uint32_t AIRTON_MESSAGE_SPACE = 100000;
|
||||
|
||||
static constexpr uint8_t AIRTON_STATE_FRAME_SIZE = 7;
|
||||
|
||||
@@ -8,8 +8,8 @@ ESPHOME_LOG_TAG(TAG, "ballu.climate");
|
||||
const uint16_t BALLU_HEADER_MARK = 9000;
|
||||
const uint16_t BALLU_HEADER_SPACE = 4500;
|
||||
const uint16_t BALLU_BIT_MARK = 575;
|
||||
const uint16_t BALLU_ONE_SPACE = 1675;
|
||||
const uint16_t BALLU_ZERO_SPACE = 550;
|
||||
static constexpr remote_base::BitTimings BALLU_BIT_TIMINGS{
|
||||
.bit_mark = BALLU_BIT_MARK, .one_space = 1675, .zero_space = 550};
|
||||
|
||||
const uint32_t BALLU_CARRIER_FREQUENCY = 38000;
|
||||
|
||||
@@ -104,13 +104,7 @@ void BalluClimate::transmit_state() {
|
||||
data->mark(BALLU_HEADER_MARK);
|
||||
data->space(BALLU_HEADER_SPACE);
|
||||
// Data
|
||||
for (uint8_t i : remote_state) {
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
data->mark(BALLU_BIT_MARK);
|
||||
bool bit = i & (1 << j);
|
||||
data->space(bit ? BALLU_ONE_SPACE : BALLU_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
data->item_bytes<BALLU_BIT_TIMINGS>(remote_state, BALLU_STATE_LENGTH);
|
||||
// Footer
|
||||
data->mark(BALLU_BIT_MARK);
|
||||
|
||||
@@ -124,21 +118,10 @@ bool BalluClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t remote_state[BALLU_STATE_LENGTH] = {0};
|
||||
// Read all bytes.
|
||||
for (int i = 0; i < BALLU_STATE_LENGTH; i++) {
|
||||
// Read bit
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (data.expect_item(BALLU_BIT_MARK, BALLU_ONE_SPACE)) {
|
||||
remote_state[i] |= 1 << j;
|
||||
|
||||
} else if (!data.expect_item(BALLU_BIT_MARK, BALLU_ZERO_SPACE)) {
|
||||
ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGVV(TAG, "Byte %d %02X", i, remote_state[i]);
|
||||
uint8_t remote_state[BALLU_STATE_LENGTH];
|
||||
if (!data.expect_bytes<BALLU_BIT_TIMINGS>(remote_state, BALLU_STATE_LENGTH)) {
|
||||
ESP_LOGV(TAG, "Data fail");
|
||||
return false;
|
||||
}
|
||||
// Validate footer
|
||||
if (!data.expect_mark(BALLU_BIT_MARK)) {
|
||||
|
||||
@@ -23,13 +23,7 @@ void DelonghiClimate::transmit_state() {
|
||||
|
||||
data->mark(DELONGHI_HEADER_MARK);
|
||||
data->space(DELONGHI_HEADER_SPACE);
|
||||
for (unsigned char b : remote_state) {
|
||||
for (uint8_t mask = 1; mask > 0; mask <<= 1) { // iterate through bit mask
|
||||
data->mark(DELONGHI_BIT_MARK);
|
||||
bool bit = b & mask;
|
||||
data->space(bit ? DELONGHI_ONE_SPACE : DELONGHI_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
data->item_bytes<DELONGHI_BIT_TIMINGS>(remote_state, DELONGHI_STATE_FRAME_SIZE);
|
||||
data->mark(DELONGHI_BIT_MARK);
|
||||
data->space(0);
|
||||
|
||||
@@ -155,27 +149,13 @@ bool DelonghiClimate::parse_state_frame_(const uint8_t frame[]) {
|
||||
}
|
||||
|
||||
bool DelonghiClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
uint8_t state_frame[DELONGHI_STATE_FRAME_SIZE] = {};
|
||||
uint8_t state_frame[DELONGHI_STATE_FRAME_SIZE];
|
||||
if (!data.expect_item(DELONGHI_HEADER_MARK, DELONGHI_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
for (uint8_t pos = 0; pos < DELONGHI_STATE_FRAME_SIZE; pos++) {
|
||||
uint8_t byte = 0;
|
||||
for (int8_t bit = 0; bit < 8; bit++) {
|
||||
if (data.expect_item(DELONGHI_BIT_MARK, DELONGHI_ONE_SPACE)) {
|
||||
byte |= 1 << bit;
|
||||
} else if (!data.expect_item(DELONGHI_BIT_MARK, DELONGHI_ZERO_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state_frame[pos] = byte;
|
||||
if (pos == 0) {
|
||||
// frame header
|
||||
if (byte != DELONGHI_ADDRESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!data.expect_bytes<DELONGHI_BIT_TIMINGS>(state_frame, DELONGHI_STATE_FRAME_SIZE) ||
|
||||
state_frame[0] != DELONGHI_ADDRESS)
|
||||
return false;
|
||||
return this->parse_state_frame_(state_frame);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ const uint32_t DELONGHI_IR_FREQUENCY = 38000;
|
||||
const uint32_t DELONGHI_HEADER_MARK = 9000;
|
||||
const uint32_t DELONGHI_HEADER_SPACE = 4500;
|
||||
const uint32_t DELONGHI_BIT_MARK = 465;
|
||||
const uint32_t DELONGHI_ONE_SPACE = 1750;
|
||||
const uint32_t DELONGHI_ZERO_SPACE = 670;
|
||||
static constexpr remote_base::BitTimings DELONGHI_BIT_TIMINGS{
|
||||
.bit_mark = DELONGHI_BIT_MARK, .one_space = 1750, .zero_space = 670};
|
||||
|
||||
// State Frame size
|
||||
const uint8_t DELONGHI_STATE_FRAME_SIZE = 8;
|
||||
|
||||
@@ -224,13 +224,7 @@ void HitachiClimate::transmit_state() {
|
||||
// Header
|
||||
data->item(HITACHI_AC424_HDR_MARK, HITACHI_AC424_HDR_SPACE);
|
||||
// Data
|
||||
for (uint8_t i : remote_state_) {
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
data->mark(HITACHI_AC424_BIT_MARK);
|
||||
bool bit = i & (1 << j);
|
||||
data->space(bit ? HITACHI_AC424_ONE_SPACE : HITACHI_AC424_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
data->item_bytes<HITACHI_AC424_BIT_TIMINGS>(remote_state_, HITACHI_AC424_STATE_LENGTH);
|
||||
// Footer
|
||||
data->item(HITACHI_AC424_BIT_MARK, HITACHI_AC424_MIN_GAP);
|
||||
}
|
||||
@@ -320,18 +314,10 @@ bool HitachiClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t recv_state[HITACHI_AC424_STATE_LENGTH] = {0};
|
||||
// Read all bytes.
|
||||
for (uint8_t pos = 0; pos < HITACHI_AC424_STATE_LENGTH; pos++) {
|
||||
// Read bit
|
||||
for (int8_t bit = 0; bit < 8; bit++) {
|
||||
if (data.expect_item(HITACHI_AC424_BIT_MARK, HITACHI_AC424_ONE_SPACE)) {
|
||||
recv_state[pos] |= 1 << bit;
|
||||
} else if (!data.expect_item(HITACHI_AC424_BIT_MARK, HITACHI_AC424_ZERO_SPACE)) {
|
||||
ESP_LOGVV(TAG, "Byte %d bit %d fail", pos, bit);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint8_t recv_state[HITACHI_AC424_STATE_LENGTH];
|
||||
if (!data.expect_bytes<HITACHI_AC424_BIT_TIMINGS>(recv_state, HITACHI_AC424_STATE_LENGTH)) {
|
||||
ESP_LOGVV(TAG, "Data fail");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate footer
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace esphome::hitachi_ac424 {
|
||||
const uint16_t HITACHI_AC424_HDR_MARK = 3416; // ac
|
||||
const uint16_t HITACHI_AC424_HDR_SPACE = 1604; // ac
|
||||
const uint16_t HITACHI_AC424_BIT_MARK = 463;
|
||||
const uint16_t HITACHI_AC424_ONE_SPACE = 1208;
|
||||
const uint16_t HITACHI_AC424_ZERO_SPACE = 372;
|
||||
static constexpr remote_base::BitTimings HITACHI_AC424_BIT_TIMINGS{
|
||||
.bit_mark = HITACHI_AC424_BIT_MARK, .one_space = 1208, .zero_space = 372};
|
||||
const uint32_t HITACHI_AC424_MIN_GAP = 100000; // just a guess.
|
||||
const uint16_t HITACHI_AC424_FREQ = 38000; // Hz.
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ const uint8_t MITSUBISHI_NIGHTMODE = 0xC1;
|
||||
|
||||
// Pulse parameters in usec
|
||||
const uint16_t MITSUBISHI_BIT_MARK = 430;
|
||||
const uint16_t MITSUBISHI_ONE_SPACE = 1250;
|
||||
const uint16_t MITSUBISHI_ZERO_SPACE = 390;
|
||||
static constexpr remote_base::BitTimings MITSUBISHI_BIT_TIMINGS{
|
||||
.bit_mark = MITSUBISHI_BIT_MARK, .one_space = 1250, .zero_space = 390};
|
||||
const uint16_t MITSUBISHI_HEADER_MARK = 3500;
|
||||
const uint16_t MITSUBISHI_HEADER_SPACE = 1700;
|
||||
const uint16_t MITSUBISHI_MIN_GAP = 17500;
|
||||
@@ -102,8 +102,8 @@ void MitsubishiClimate::transmit_state() {
|
||||
// Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00
|
||||
// Byte 16: Left vane control (for specific models). Constants match right vane controls.
|
||||
// Byte 17: Checksum: SUM[Byte0...Byte16]
|
||||
uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t remote_state[MITSUBISHI_FRAME_SIZE] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_HEAT:
|
||||
@@ -259,13 +259,7 @@ void MitsubishiClimate::transmit_state() {
|
||||
data->mark(MITSUBISHI_HEADER_MARK);
|
||||
data->space(MITSUBISHI_HEADER_SPACE);
|
||||
// Data
|
||||
for (uint8_t i : remote_state) {
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
data->mark(MITSUBISHI_BIT_MARK);
|
||||
bool bit = i & (1 << j);
|
||||
data->space(bit ? MITSUBISHI_ONE_SPACE : MITSUBISHI_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
data->item_bytes<MITSUBISHI_BIT_TIMINGS>(remote_state, sizeof(remote_state));
|
||||
// Footer
|
||||
if (r == 0) {
|
||||
data->mark(MITSUBISHI_BIT_MARK);
|
||||
@@ -280,33 +274,21 @@ void MitsubishiClimate::transmit_state() {
|
||||
bool MitsubishiClimate::parse_state_frame_(const uint8_t frame[]) { return false; }
|
||||
|
||||
bool MitsubishiClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
uint8_t state_frame[18] = {};
|
||||
uint8_t state_frame[MITSUBISHI_FRAME_SIZE];
|
||||
|
||||
if (!data.expect_item(MITSUBISHI_HEADER_MARK, MITSUBISHI_HEADER_SPACE)) {
|
||||
ESP_LOGV(TAG, "Header fail");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t pos = 0; pos < 18; pos++) {
|
||||
uint8_t byte = 0;
|
||||
for (int8_t bit = 0; bit < 8; bit++) {
|
||||
if (data.expect_item(MITSUBISHI_BIT_MARK, MITSUBISHI_ONE_SPACE)) {
|
||||
byte |= 1 << bit;
|
||||
} else if (!data.expect_item(MITSUBISHI_BIT_MARK, MITSUBISHI_ZERO_SPACE)) {
|
||||
ESP_LOGV(TAG, "Byte %d bit %d fail", pos, bit);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state_frame[pos] = byte;
|
||||
|
||||
// Check Header && Footer. Byte 16 only ever carries the left vane position (bits 3,4,5).
|
||||
if ((pos == 0 && byte != MITSUBISHI_BYTE00) || (pos == 1 && byte != MITSUBISHI_BYTE01) ||
|
||||
(pos == 2 && byte != MITSUBISHI_BYTE02) || (pos == 3 && byte != MITSUBISHI_BYTE03) ||
|
||||
(pos == 4 && byte != MITSUBISHI_BYTE04) || (pos == 13 && byte != MITSUBISHI_BYTE13) ||
|
||||
(pos == 16 && (byte & ~MITSUBISHI_VERTICAL_VANE_MASK) != 0)) {
|
||||
ESP_LOGV(TAG, "Bytes 0,1,2,3,4,13 or 16 fail - invalid value");
|
||||
return false;
|
||||
}
|
||||
// Check Header && Footer. Byte 16 only ever carries the left vane position (bits 3,4,5).
|
||||
if (!data.expect_bytes<MITSUBISHI_BIT_TIMINGS>(state_frame, sizeof(state_frame)) ||
|
||||
state_frame[0] != MITSUBISHI_BYTE00 || state_frame[1] != MITSUBISHI_BYTE01 ||
|
||||
state_frame[2] != MITSUBISHI_BYTE02 || state_frame[3] != MITSUBISHI_BYTE03 ||
|
||||
state_frame[4] != MITSUBISHI_BYTE04 || state_frame[13] != MITSUBISHI_BYTE13 ||
|
||||
(state_frame[16] & ~MITSUBISHI_VERTICAL_VANE_MASK) != 0) {
|
||||
ESP_LOGV(TAG, "Bit decode or bytes 0,1,2,3,4,13 or 16 fail");
|
||||
return false;
|
||||
}
|
||||
|
||||
// On/Off and Mode
|
||||
|
||||
Reference in New Issue
Block a user