From bf84a00321302c808ef85c7eea99095527718dd4 Mon Sep 17 00:00:00 2001 From: David Conran Date: Thu, 20 May 2021 16:32:19 +1000 Subject: [PATCH] [HAIER_AC176] Basic support for `HAIER_AC176` 176 bit protocol. (#1481) * Add `sendHaierAC176()` & `decodeHaierAC176()` * Additional changes to support the new protocol. * Unit test coverage for send and decode. * Add housekeeping tests for Haier family * Minor code clean-up in the unit tests. For #1480 --- src/IRrecv.cpp | 4 + src/IRrecv.h | 6 ++ src/IRremoteESP8266.h | 15 +++- src/IRsend.cpp | 7 ++ src/IRsend.h | 11 ++- src/IRtext.cpp | 1 + src/IRutils.cpp | 1 + src/ir_Haier.cpp | 53 ++++++++++++- src/ir_Haier.h | 2 + src/locale/defaults.h | 3 + test/ir_Haier_test.cpp | 166 ++++++++++++++++++++++++++++++++--------- 11 files changed, 223 insertions(+), 46 deletions(-) diff --git a/src/IRrecv.cpp b/src/IRrecv.cpp index 36e0c0e83..545c0d48a 100644 --- a/src/IRrecv.cpp +++ b/src/IRrecv.cpp @@ -770,6 +770,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Haier AC YR-W02 decode"); if (decodeHaierACYRW02(results, offset)) return true; #endif +#if DECODE_HAIER_AC176 + DPRINTLN("Attempting Haier AC 176 bit decode"); + if (decodeHaierAC176(results, offset)) return true; +#endif // DECODE_HAIER_AC176 #if DECODE_HITACHI_AC424 // HitachiAc424 should be checked before HitachiAC, HitachiAC2, // & HitachiAC184 diff --git a/src/IRrecv.h b/src/IRrecv.h index b0b43aa9b..ca67bb813 100644 --- a/src/IRrecv.h +++ b/src/IRrecv.h @@ -561,6 +561,12 @@ class IRrecv { const uint16_t nbits = kHaierACYRW02Bits, const bool strict = true); #endif +#if DECODE_HAIER_AC176 + bool decodeHaierAC176(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kHaierAC176Bits, + const bool strict = true); +#endif // DECODE_HAIER_AC176 #if (DECODE_HITACHI_AC || DECODE_HITACHI_AC2 || DECODE_HITACHI_AC344) bool decodeHitachiAC(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kHitachiAcBits, diff --git a/src/IRremoteESP8266.h b/src/IRremoteESP8266.h index 115e3865b..9712bebbd 100644 --- a/src/IRremoteESP8266.h +++ b/src/IRremoteESP8266.h @@ -747,6 +747,13 @@ #define SEND_TRUMA _IR_ENABLE_DEFAULT_ #endif // SEND_TRUMA +#ifndef DECODE_HAIER_AC176 +#define DECODE_HAIER_AC176 _IR_ENABLE_DEFAULT_ +#endif // DECODE_HAIER_AC176 +#ifndef SEND_HAIER_AC176 +#define SEND_HAIER_AC176 _IR_ENABLE_DEFAULT_ +#endif // SEND_HAIER_AC176 + #if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \ DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \ DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \ @@ -759,7 +766,7 @@ DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \ DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3 || \ DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC || \ - DECODE_VOLTAS || DECODE_MIRAGE) + DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176) // Add any DECODE to the above if it uses result->state (see kStateSizeMax) // you might also want to add the protocol to hasACState function #define DECODE_AC true // We need some common infrastructure for decoding A/Cs. @@ -899,8 +906,9 @@ enum decode_type_t { ECOCLIM, XMP, TRUMA, // 100 + HAIER_AC176, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = TRUMA, + kLastDecodeType = HAIER_AC176, }; // Message lengths & required repeat values @@ -992,6 +1000,9 @@ const uint16_t kHaierAcDefaultRepeat = kNoRepeat; const uint16_t kHaierACYRW02StateLength = 14; const uint16_t kHaierACYRW02Bits = kHaierACYRW02StateLength * 8; const uint16_t kHaierAcYrw02DefaultRepeat = kNoRepeat; +const uint16_t kHaierAC176StateLength = 22; +const uint16_t kHaierAC176Bits = kHaierAC176StateLength * 8; +const uint16_t kHaierAc176DefaultRepeat = kNoRepeat; const uint16_t kHitachiAcStateLength = 28; const uint16_t kHitachiAcBits = kHitachiAcStateLength * 8; const uint16_t kHitachiAcDefaultRepeat = kNoRepeat; diff --git a/src/IRsend.cpp b/src/IRsend.cpp index c32eedea4..0bb223c9b 100644 --- a/src/IRsend.cpp +++ b/src/IRsend.cpp @@ -700,6 +700,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kHaierACBits; case HAIER_AC_YRW02: return kHaierACYRW02Bits; + case HAIER_AC176: + return kHaierAC176Bits; case HITACHI_AC: return kHitachiAcBits; case HITACHI_AC1: @@ -1143,6 +1145,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendHaierACYRW02(state, nbytes); break; #endif // SEND_HAIER_AC_YRW02 +#if SEND_HAIER_AC176 + case HAIER_AC176: + sendHaierAC176(state, nbytes); + break; +#endif // SEND_HAIER_AC176 #if SEND_HITACHI_AC case HITACHI_AC: sendHitachiAC(state, nbytes); diff --git a/src/IRsend.h b/src/IRsend.h index 99b103f8f..20fd7d0c6 100644 --- a/src/IRsend.h +++ b/src/IRsend.h @@ -522,16 +522,21 @@ class IRsend { void sendCarrierAC64(uint64_t data, uint16_t nbits = kCarrierAc64Bits, uint16_t repeat = kCarrierAc64MinRepeat); #endif -#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) +#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) void sendHaierAC(const unsigned char data[], const uint16_t nbytes = kHaierACStateLength, const uint16_t repeat = kHaierAcDefaultRepeat); -#endif +#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) #if SEND_HAIER_AC_YRW02 void sendHaierACYRW02(const unsigned char data[], const uint16_t nbytes = kHaierACYRW02StateLength, const uint16_t repeat = kHaierAcYrw02DefaultRepeat); -#endif +#endif // SEND_HAIER_AC_YRW02 +#if SEND_HAIER_AC176 + void sendHaierAC176(const unsigned char data[], + const uint16_t nbytes = kHaierAC176StateLength, + const uint16_t repeat = kHaierAc176DefaultRepeat); +#endif // SEND_HAIER_AC176 #if SEND_HITACHI_AC void sendHitachiAC(const unsigned char data[], const uint16_t nbytes = kHitachiAcStateLength, diff --git a/src/IRtext.cpp b/src/IRtext.cpp index 722074d67..55737c780 100644 --- a/src/IRtext.cpp +++ b/src/IRtext.cpp @@ -285,5 +285,6 @@ const PROGMEM char *kAllProtocolNamesStr = D_STR_ECOCLIM "\x0" D_STR_XMP "\x0" D_STR_TRUMA "\x0" + D_STR_HAIER_AC176 "\x0" ///< New protocol strings should be added just above this line. "\x0"; ///< This string requires double null termination. diff --git a/src/IRutils.cpp b/src/IRutils.cpp index 3ec5303e6..5d16c850c 100644 --- a/src/IRutils.cpp +++ b/src/IRutils.cpp @@ -145,6 +145,7 @@ bool hasACState(const decode_type_t protocol) { case GREE: case HAIER_AC: case HAIER_AC_YRW02: + case HAIER_AC176: case HITACHI_AC: case HITACHI_AC1: case HITACHI_AC2: diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index 94d1bd1d2..2a01f3b36 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -1,4 +1,4 @@ -// Copyright 2018 crankyoldgit +// Copyright 2018-2021 crankyoldgit /// @file /// @brief Support for Haier A/C protocols. /// The specifics of reverse engineering the protocols details: @@ -8,6 +8,7 @@ /// @see https://www.dropbox.com/s/mecyib3lhdxc8c6/IR%20data%20reverse%20engineering.xlsx?dl=0 /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/485 /// @see https://www.dropbox.com/sh/w0bt7egp0fjger5/AADRFV6Wg4wZskJVdFvzb8Z0a?dl=0&preview=haer2.ods +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1480 #include "ir_Haier.h" #include @@ -42,7 +43,7 @@ using irutils::minsToString; _.x##Mins = mins % 60;\ } while (0) -#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) +#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) /// Send a Haier A/C formatted message. (HSU07-HEA03 remote) /// Status: STABLE / Known to be working. /// @param[in] data The message to be sent. @@ -63,11 +64,11 @@ void IRsend::sendHaierAC(const unsigned char data[], const uint16_t nbytes, 50); } } -#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) +#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) #if SEND_HAIER_AC_YRW02 /// Send a Haier YR-W02 remote A/C formatted message. -/// Status: Alpha / Untested on a real device. +/// Status: STABLE / Known to be working. /// @param[in] data The message to be sent. /// @param[in] nbytes The number of bytes of message to be sent. /// @param[in] repeat The number of times the command is to be repeated. @@ -77,6 +78,18 @@ void IRsend::sendHaierACYRW02(const unsigned char data[], const uint16_t nbytes, } #endif // SEND_HAIER_AC_YRW02 +#if SEND_HAIER_AC176 +/// Send a Haier 176 bit remote A/C formatted message. +/// Status: STABLE / Known to be working. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +void IRsend::sendHaierAC176(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes >= kHaierAC176StateLength) sendHaierAC(data, nbytes, repeat); +} +#endif // SEND_HAIER_AC176 + /// Class constructor /// @param[in] pin GPIO to be used when sending. /// @param[in] inverted Is the output signal to be inverted? @@ -1039,3 +1052,35 @@ bool IRrecv::decodeHaierACYRW02(decode_results* results, uint16_t offset, return true; } #endif // DECODE_HAIER_AC_YRW02 + +#if DECODE_HAIER_AC176 +/// Decode the supplied Haier 176 bit remote A/C message. +/// Status: STABLE / Known to be working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// result. +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +/// @return A boolean. True if it can decode it, false if it can't. +bool IRrecv::decodeHaierAC176(decode_results* results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict) { + if (nbits != kHaierAC176Bits) + return false; // Not strictly a HAIER_AC176 message. + } + + // The protocol is almost exactly the same as HAIER_AC + if (!decodeHaierAC(results, offset, nbits, false)) return false; + + // Compliance + if (strict) { + if (results->state[0] != kHaierAcYrw02Prefix) return false; + } + + // Success + // It looks correct, but we haven't check the checksum etc. + results->decode_type = HAIER_AC176; + return true; +} +#endif // DECODE_HAIER_AC176 diff --git a/src/ir_Haier.h b/src/ir_Haier.h index e79292028..df696642c 100644 --- a/src/ir_Haier.h +++ b/src/ir_Haier.h @@ -13,6 +13,8 @@ // Brand: Haier, Model: HSU07-HEA03 remote (HAIER_AC) // Brand: Haier, Model: YR-W02 remote (HAIER_AC_YRW02) // Brand: Haier, Model: HSU-09HMC203 A/C (HAIER_AC_YRW02) +// Brand: Mabe, Model: MMI18HDBWCA6MI8 A/C (HAIER_AC176) +// Brand: Mabe, Model: V12843 HJ200223 remote (HAIER_AC176) #ifndef IR_HAIER_H_ #define IR_HAIER_H_ diff --git a/src/locale/defaults.h b/src/locale/defaults.h index ba29e7895..b22bd45be 100644 --- a/src/locale/defaults.h +++ b/src/locale/defaults.h @@ -586,6 +586,9 @@ #ifndef D_STR_HAIER_AC_YRW02 #define D_STR_HAIER_AC_YRW02 "HAIER_AC_YRW02" #endif // D_STR_HAIER_AC_YRW02 +#ifndef D_STR_HAIER_AC176 +#define D_STR_HAIER_AC176 "HAIER_AC176" +#endif // D_STR_HAIER_AC176 #ifndef D_STR_HITACHI_AC #define D_STR_HITACHI_AC "HITACHI_AC" #endif // D_STR_HITACHI_AC diff --git a/test/ir_Haier_test.cpp b/test/ir_Haier_test.cpp index 87fe41b47..77b475f6e 100644 --- a/test/ir_Haier_test.cpp +++ b/test/ir_Haier_test.cpp @@ -12,7 +12,7 @@ // Test sending typical data only. TEST(TestSendHaierAC, SendDataOnly) { - IRsendTest irsend(0); + IRsendTest irsend(kGpioUnused); irsend.begin(); uint8_t haier_zero[kHaierACStateLength] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -56,7 +56,7 @@ TEST(TestSendHaierAC, SendDataOnly) { // Test sending typical data with repeats. TEST(TestSendHaierAC, SendWithRepeats) { - IRsendTest irsend(0); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -105,7 +105,7 @@ TEST(TestSendHaierAC, SendWithRepeats) { // Tests for IRHaierAC class. TEST(TestHaierACClass, Command) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); haier.setCommand(kHaierAcCmdOff); @@ -145,7 +145,7 @@ TEST(TestHaierACClass, Command) { } TEST(TestHaierACClass, OperatingMode) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); haier.setMode(kHaierAcAuto); @@ -177,7 +177,7 @@ TEST(TestHaierACClass, OperatingMode) { } TEST(TestHaierACClass, Temperature) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); haier.setTemp(kHaierAcMinTemp); @@ -218,7 +218,7 @@ TEST(TestHaierACClass, Temperature) { } TEST(TestHaierACClass, FanSpeed) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); haier.setFan(kHaierAcFanLow); haier.setCommand(kHaierAcCmdOn); @@ -241,7 +241,7 @@ TEST(TestHaierACClass, FanSpeed) { } TEST(TestHaierACClass, Swing) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); haier.setFan(kHaierAcFanLow); haier.setCommand(kHaierAcCmdOn); @@ -263,7 +263,7 @@ TEST(TestHaierACClass, Swing) { } TEST(TestHaierACClass, CurrentTime) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); EXPECT_EQ(0, haier.getCurrTime()); @@ -290,7 +290,7 @@ TEST(TestHaierACClass, CurrentTime) { } TEST(TestHaierACClass, Timers) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.begin(); haier.setCommand(kHaierAcCmdOn); @@ -347,7 +347,7 @@ TEST(TestHaierACClass, Timers) { } TEST(TestHaierACClass, MessageConstuction) { - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); EXPECT_EQ( "Command: 1 (On), Mode: 0 (Auto), Temp: 25C, Fan: 1 (Low), " @@ -420,7 +420,7 @@ TEST(TestHaierACClass, MessageConstuction) { // Tests for the IRHaierACYRW02 class. TEST(TestHaierACYRW02Class, Button) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setButton(kHaierAcYrw02ButtonPower); @@ -439,7 +439,7 @@ TEST(TestHaierACYRW02Class, Button) { } TEST(TestHaierACYRW02Class, OperatingMode) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setButton(kHaierAcYrw02ButtonPower); @@ -473,7 +473,7 @@ TEST(TestHaierACYRW02Class, OperatingMode) { } TEST(TestHaierACYRW02Class, Temperature) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setTemp(kHaierAcMinTemp); @@ -514,7 +514,7 @@ TEST(TestHaierACYRW02Class, Temperature) { } TEST(TestHaierACYRW02Class, HealthMode) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setHealth(true); @@ -532,7 +532,7 @@ TEST(TestHaierACYRW02Class, HealthMode) { } TEST(TestHaierACYRW02Class, Power) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setPower(true); @@ -555,7 +555,7 @@ TEST(TestHaierACYRW02Class, Power) { } TEST(TestHaierACYRW02Class, SleepMode) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setSleep(true); @@ -573,7 +573,7 @@ TEST(TestHaierACYRW02Class, SleepMode) { } TEST(TestHaierACYRW02Class, TurboMode) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setTurbo(kHaierAcYrw02TurboOff); @@ -596,7 +596,7 @@ TEST(TestHaierACYRW02Class, TurboMode) { } TEST(TestHaierACYRW02Class, Fan) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setFan(kHaierAcYrw02FanAuto); @@ -625,7 +625,7 @@ TEST(TestHaierACYRW02Class, Fan) { } TEST(TestHaierACYRW02Class, Swing) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.begin(); haier.setSwing(kHaierAcYrw02SwingOff); @@ -670,7 +670,7 @@ TEST(TestHaierACYRW02Class, Swing) { } TEST(TestHaierACYRW02Class, MessageConstuction) { - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); EXPECT_EQ( "Power: On, Button: 5 (Power), Mode: 0 (Auto), Temp: 25C," @@ -703,7 +703,7 @@ TEST(TestHaierACYRW02Class, RealStates) { 0xA6, 0xE1, 0x00, 0x00, 0x40, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x6E}; - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.setRaw(expectedState1); EXPECT_EQ( "Power: On, Button: 7 (Health), Mode: 4 (Heat), Temp: 30C," @@ -758,8 +758,8 @@ TEST(TestHaierACYRW02Class, RealStates) { // Decode normal "synthetic" messages. TEST(TestDecodeHaierAC, NormalDecodeWithStrict) { - IRsendTest irsend(0); - IRrecv irrecv(0); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x01, 0x20, 0x01, 0x00, @@ -789,8 +789,8 @@ TEST(TestDecodeHaierAC, NormalDecodeWithStrict) { // Decode a "real" example message. TEST(TestDecodeHaierAC, RealExample1) { - IRsendTest irsend(0); - IRrecv irrecv(0); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -831,8 +831,8 @@ TEST(TestDecodeHaierAC, RealExample1) { // Decode a "real" example message. TEST(TestDecodeHaierAC, RealExample2) { - IRsendTest irsend(0); - IRrecv irrecv(0); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -863,7 +863,7 @@ TEST(TestDecodeHaierAC, RealExample2) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.setRaw(irsend.capture.state); EXPECT_EQ( "Command: 6 (Temp Up), Mode: 1 (Cool), Temp: 22C, Fan: 1 (Low), " @@ -874,8 +874,8 @@ TEST(TestDecodeHaierAC, RealExample2) { // Decode a "real" example message. TEST(TestDecodeHaierAC, RealExample3) { - IRsendTest irsend(0); - IRrecv irrecv(0); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -906,7 +906,7 @@ TEST(TestDecodeHaierAC, RealExample3) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); - IRHaierAC haier(0); + IRHaierAC haier(kGpioUnused); haier.setRaw(irsend.capture.state); EXPECT_EQ( "Command: 12 (Health), Mode: 1 (Cool), Temp: 30C, Fan: 1 (Low), " @@ -917,8 +917,8 @@ TEST(TestDecodeHaierAC, RealExample3) { // Decode normal "synthetic" messages. TEST(TestDecodeHaierAC_YRW02, NormalDecode) { - IRsendTest irsend(0); - IRrecv irrecv(0); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); uint8_t expectedState[kHaierACYRW02StateLength] = { @@ -937,8 +937,8 @@ TEST(TestDecodeHaierAC_YRW02, NormalDecode) { // Decode a "real" example message. TEST(TestDecodeHaierAC_YRW02, RealExample) { - IRsendTest irsend(0); - IRrecv irrecv(0); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); irsend.reset(); @@ -976,7 +976,7 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); - IRHaierACYRW02 haier(0); + IRHaierACYRW02 haier(kGpioUnused); haier.setRaw(irsend.capture.state); EXPECT_EQ( "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 17C," @@ -990,7 +990,7 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) { TEST(TestHaierAcIssues, Issue668) { IRHaierAC ac(0); IRHaierAC acText(1); - IRrecv irrecv(0); + IRrecv irrecv(kGpioUnused); ac.begin(); // Turn on the AC. @@ -1135,3 +1135,95 @@ TEST(TestHaierACYRW02Class, toCommon) { ASSERT_FALSE(ac.toCommon().beep); ASSERT_EQ(-1, ac.toCommon().clock); } + +TEST(TestDecodeHaierAC176, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1480 + const uint16_t rawData[357] = { + 3096, 2948, 3048, 4388, 588, 1610, 614, 498, 586, 1612, 612, 500, 612, + 500, 586, 1610, 588, 1612, 612, 502, 586, 1612, 612, 500, 612, 500, 614, + 500, 612, 498, 586, 1610, 586, 1612, 612, 502, 612, 500, 612, 500, 612, + 500, 612, 500, 612, 500, 612, 500, 612, 500, 612, 504, 612, 500, 612, 500, + 612, 500, 612, 500, 612, 500, 612, 500, 612, 500, 612, 502, 614, 498, 586, + 1612, 612, 500, 612, 500, 612, 500, 612, 500, 612, 500, 612, 502, 586, + 1612, 612, 500, 586, 1610, 612, 500, 612, 498, 612, 500, 614, 478, 634, + 502, 612, 500, 612, 500, 612, 500, 612, 500, 612, 500, 612, 500, 612, 498, + 614, 504, 612, 500, 614, 500, 586, 1612, 612, 500, 612, 500, 612, 500, + 612, 500, 612, 502, 612, 500, 612, 500, 612, 500, 612, 500, 612, 500, 612, + 500, 612, 500, 612, 504, 614, 500, 612, 500, 612, 498, 614, 500, 612, 500, + 612, 500, 612, 500, 612, 482, 632, 500, 612, 502, 610, 500, 614, 500, 612, + 500, 612, 500, 612, 480, 632, 504, 612, 480, 632, 500, 612, 500, 612, 480, + 632, 500, 612, 500, 612, 500, 612, 502, 612, 500, 612, 500, 612, 500, 612, + 500, 612, 500, 586, 1612, 612, 500, 586, 1616, 612, 500, 612, 500, 586, + 1610, 588, 1612, 612, 502, 612, 500, 614, 498, 586, 1614, 586, 1612, 612, + 500, 586, 1610, 586, 1592, 632, 498, 586, 1610, 588, 1610, 586, 1614, 614, + 500, 612, 480, 632, 500, 612, 500, 612, 500, 612, 500, 614, 498, 612, 500, + 614, 500, 614, 500, 612, 500, 612, 500, 614, 498, 614, 498, 614, 500, 612, + 504, 612, 500, 612, 500, 612, 500, 612, 498, 612, 502, 612, 500, 614, 498, + 612, 502, 612, 500, 612, 498, 614, 500, 612, 500, 612, 500, 612, 500, 612, + 500, 614, 502, 612, 500, 614, 478, 634, 498, 614, 500, 612, 500, 612, 500, + 612, 500, 612, 482, 634, 500, 612, 500, 612, 500, 612, 500, 614, 498, 614, + 500, 612, 480, 632, 502, 586, 1610, 614, 478, 608, 1610, 588, 1610, 612, + 498, 586, 1610, 588, 1610, 586, 1606, 612}; // UNKNOWN ABFAD961 + + irsend.sendRaw(rawData, 357, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(HAIER_AC176, irsend.capture.decode_type); + EXPECT_EQ(kHaierAC176Bits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + const uint8_t expectedState[kHaierAC176StateLength] = { + 0xA6, 0x86, 0x00, 0x00, 0x40, 0xA0, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x31, + 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7}; + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +// Decode normal "synthetic" messages. +TEST(TestDecodeHaierAC176, SyntheticDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + const uint8_t expectedState[kHaierAC176StateLength] = { + 0xA6, 0x86, 0x00, 0x00, 0x40, 0xA0, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x31, + 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7}; + + irsend.reset(); + irsend.sendHaierAC176(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(HAIER_AC176, irsend.capture.decode_type); + EXPECT_EQ(kHaierAC176Bits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("HAIER_AC", typeToString(decode_type_t::HAIER_AC)); + ASSERT_EQ(decode_type_t::HAIER_AC, strToDecodeType("HAIER_AC")); + ASSERT_TRUE(hasACState(decode_type_t::HAIER_AC)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HAIER_AC)); + ASSERT_EQ(kHaierACBits, IRsend::defaultBits(decode_type_t::HAIER_AC)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::HAIER_AC)); + + ASSERT_EQ("HAIER_AC_YRW02", typeToString(decode_type_t::HAIER_AC_YRW02)); + ASSERT_EQ(decode_type_t::HAIER_AC_YRW02, strToDecodeType("HAIER_AC_YRW02")); + ASSERT_TRUE(hasACState(decode_type_t::HAIER_AC_YRW02)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HAIER_AC_YRW02)); + ASSERT_EQ(kHaierACYRW02Bits, + IRsend::defaultBits(decode_type_t::HAIER_AC_YRW02)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::HAIER_AC_YRW02)); + + ASSERT_EQ("HAIER_AC176", typeToString(decode_type_t::HAIER_AC176)); + ASSERT_EQ(decode_type_t::HAIER_AC176, strToDecodeType("HAIER_AC176")); + ASSERT_TRUE(hasACState(decode_type_t::HAIER_AC176)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HAIER_AC176)); + ASSERT_EQ(kHaierAC176Bits, IRsend::defaultBits(decode_type_t::HAIER_AC176)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::HAIER_AC176)); +}