From 552e0bbe26c174bd60bf6b058256a451326bbd3e Mon Sep 17 00:00:00 2001 From: PtilopsisLeucotis Date: Thu, 11 Nov 2021 11:17:52 +0300 Subject: [PATCH 1/4] [HAIER_AC176/HAIER_AC_YRW02] Add support A/B unit setting * Add `model` parameter in `IRac::haier176()` * Add `Model` parameter in `IRHaierAC176` state * Add `getModel()` and `setModel()` methods * Bump heap size for `toString()` method * Update `toString()` method * Update related tests --- src/IRac.cpp | 10 ++-- src/IRac.h | 10 ++-- src/IRsend.h | 6 +++ src/IRtext.cpp | 2 + src/IRtext.h | 2 + src/IRutils.cpp | 10 ++++ src/ir_Haier.cpp | 36 +++++++++++--- src/ir_Haier.h | 8 +++- src/locale/defaults.h | 6 +++ test/IRac_test.cpp | 35 +++++++------- test/ir_Haier_test.cpp | 104 ++++++++++++++++++++--------------------- 11 files changed, 143 insertions(+), 86 deletions(-) diff --git a/src/IRac.cpp b/src/IRac.cpp index 89e99a0b0..ba70ae017 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -1114,6 +1114,7 @@ void IRac::haier(IRHaierAC *ac, #if SEND_HAIER_AC176 /// Send a Haier 176 bit A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRHaierAC176 object to use. +/// @param[in] model The A/C model to use. /// @param[in] on The power setting. /// @param[in] mode The operation mode setting. /// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit. @@ -1125,7 +1126,7 @@ void IRac::haier(IRHaierAC *ac, /// @param[in] quiet Run the device in quiet mode. /// @param[in] filter Turn on the (ion/pollen/etc) filter mode. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. -void IRac::haier176(IRHaierAC176 *ac, +void IRac::haier176(IRHaierAC176 *ac, const haier_ac176_remote_model_t model, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, @@ -1134,6 +1135,7 @@ void IRac::haier176(IRHaierAC176 *ac, const bool turbo, const bool quiet, const bool filter, const int16_t sleep) { ac->begin(); + ac->setModel(model); ac->setMode(ac->convertMode(mode)); ac->setUseFahrenheit(!celsius); ac->setTemp(degrees); @@ -2792,9 +2794,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HAIER_AC176: { IRHaierAC176 ac(_pin, _inverted, _modulation); - haier176(&ac, send.power, send.mode, send.celsius, send.degrees, - send.fanspeed, send.swingv, send.swingh, send.turbo, - send.filter, send.sleep); + haier176(&ac, (haier_ac176_remote_model_t)send.model, send.power, + send.mode, send.celsius, send.degrees, send.fanspeed, + send.swingv, send.swingh, send.turbo, send.filter, send.sleep); break; } #endif // SEND_HAIER_AC176 diff --git a/src/IRac.h b/src/IRac.h index 56df0fa46..afa4bcee0 100644 --- a/src/IRac.h +++ b/src/IRac.h @@ -261,11 +261,11 @@ void electra(IRElectraAc *ac, #endif // SEND_HAIER_AC #if SEND_HAIER_AC176 void haier176(IRHaierAC176 *ac, - const bool on, const stdAc::opmode_t mode, - const bool celsius, const float degrees, - const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, - const stdAc::swingh_t swingh, const bool turbo, - const bool quiet, const bool filter, + const haier_ac176_remote_model_t model, const bool on, + const stdAc::opmode_t mode, const bool celsius, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + const bool turbo, const bool quiet, const bool filter, const int16_t sleep = -1); #endif // SEND_HAIER_AC176 #if SEND_HAIER_AC_YRW02 diff --git a/src/IRsend.h b/src/IRsend.h index 7ab8dafd4..1854c8166 100644 --- a/src/IRsend.h +++ b/src/IRsend.h @@ -136,6 +136,12 @@ enum gree_ac_remote_model_t { YBOFB, // (2) Green, YBOFB2, YAPOF3 }; +/// HAIER_AC176 A/C model numbers +enum haier_ac176_remote_model_t { + V9014557_A = 1, // (1) V9014557 Remote in "A" setting. (Default) + V9014557_B, // (2) V9014557 Remote in "B" setting. +}; + /// HITACHI_AC1 A/C model numbers enum hitachi_ac1_remote_model_t { R_LT0541_HTA_A = 1, // (1) R-LT0541-HTA Remote in "A" setting. (Default) diff --git a/src/IRtext.cpp b/src/IRtext.cpp index 0b6a55b5f..ef9f4eb3c 100644 --- a/src/IRtext.cpp +++ b/src/IRtext.cpp @@ -228,6 +228,8 @@ IRTEXT_CONST_STRING(kBitsStr, D_STR_BITS); ///< "Bits" // Model Names IRTEXT_CONST_STRING(kYaw1fStr, D_STR_YAW1F); ///< "YAW1F" IRTEXT_CONST_STRING(kYbofbStr, D_STR_YBOFB); ///< "YBOFB" +IRTEXT_CONST_STRING(kV9014557AStr, D_STR_V9014557_A); ///< "V9014557-A" +IRTEXT_CONST_STRING(kV9014557BStr, D_STR_V9014557_B); ///< "V9014557-B" IRTEXT_CONST_STRING(kRlt0541htaaStr, D_STR_RLT0541HTA_A); ///< "R-LT0541-HTA-A" IRTEXT_CONST_STRING(kRlt0541htabStr, D_STR_RLT0541HTA_B); ///< "R-LT0541-HTA-B" IRTEXT_CONST_STRING(kArrah2eStr, D_STR_ARRAH2E); ///< "ARRAH2E" diff --git a/src/IRtext.h b/src/IRtext.h index 2b4e45859..ee8ea5934 100644 --- a/src/IRtext.h +++ b/src/IRtext.h @@ -218,6 +218,8 @@ extern IRTEXT_CONST_PTR(kTypeStr); extern IRTEXT_CONST_PTR(kUnknownStr); extern IRTEXT_CONST_PTR(kUpperStr); extern IRTEXT_CONST_PTR(kUpStr); +extern IRTEXT_CONST_PTR(kV9014557AStr); +extern IRTEXT_CONST_PTR(kV9014557BStr); extern IRTEXT_CONST_PTR(kVaneStr); extern IRTEXT_CONST_PTR(kWallStr); extern IRTEXT_CONST_PTR(kWeeklyTimerStr); diff --git a/src/IRutils.cpp b/src/IRutils.cpp index 148c6ea35..d3e86287d 100644 --- a/src/IRutils.cpp +++ b/src/IRutils.cpp @@ -606,6 +606,16 @@ namespace irutils { default: return kUnknownStr; } break; + case decode_type_t::HAIER_AC176: + switch (model) { + case haier_ac176_remote_model_t::V9014557_A: + return kV9014557AStr; + case haier_ac176_remote_model_t::V9014557_B: + return kV9014557BStr; + default: + return kUnknownStr; + } + break; case decode_type_t::HITACHI_AC1: switch (model) { case hitachi_ac1_remote_model_t::R_LT0541_HTA_A: diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index 1ba09cfb5..78c2f005d 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -32,6 +32,7 @@ using irutils::addBoolToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; using irutils::addSwingHToString; using irutils::addFanToString; using irutils::addTempToString; @@ -582,7 +583,7 @@ bool IRHaierAC176::validChecksum(const uint8_t state[], const uint16_t length) { /// Reset the internal state to a fixed known good state. void IRHaierAC176::stateReset(void) { std::memset(_.raw, 0, sizeof _.raw); - _.Prefix = kHaierAcYrw02Prefix; + _.Model = kHaierAcYrw02ModelA; _.Prefix2 = kHaierAc176Prefix; _.Temp = kHaierAcYrw02DefTempC - kHaierAcYrw02MinTempC; _.Health = true; @@ -624,6 +625,27 @@ void IRHaierAC176::setButton(uint8_t button) { } } +/// Get/Detect the model of the A/C. +/// @return The enum of the compatible model. +haier_ac176_remote_model_t IRHaierAC176::getModel(void) const { + switch (_.Model) { + case kHaierAcYrw02ModelB: return haier_ac176_remote_model_t::V9014557_B; + default: return haier_ac176_remote_model_t::V9014557_A; + } +} + +/// Set the model of the A/C to emulate. +/// @param[in] model The enum of the appropriate model. +void IRHaierAC176::setModel(haier_ac176_remote_model_t model) { + switch (model) { + case haier_ac176_remote_model_t::V9014557_B: + _.Model = kHaierAcYrw02ModelB; + break; + default: + _.Model = kHaierAcYrw02ModelA; + } +} + /// Get the Button/Command setting of the A/C. /// @return The value of the button/command that was pressed. uint8_t IRHaierAC176::getButton(void) const { @@ -1106,7 +1128,7 @@ stdAc::swingh_t IRHaierAC176::toCommonSwingH(const uint8_t pos) { stdAc::state_t IRHaierAC176::toCommon(void) const { stdAc::state_t result; result.protocol = decode_type_t::HAIER_AC_YRW02; - result.model = -1; // No models used. + result.model = getModel(); result.power = _.Power; result.mode = toCommonMode(_.Mode); result.celsius = !_.UseFahrenheit; @@ -1131,8 +1153,9 @@ stdAc::state_t IRHaierAC176::toCommon(void) const { /// @return A human readable string. String IRHaierAC176::toString(void) const { String result = ""; - result.reserve(260); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(_.Power, kPowerStr, false); + result.reserve(280); // Reserve some heap for the string to reduce fragging. + result += addModelToString(decode_type_t::HAIER_AC176, getModel(), false); + result += addBoolToString(_.Power, kPowerStr, true); uint8_t cmd = _.Button; result += addIntToString(cmd, kButtonStr); result += kSpaceLBraceStr; @@ -1367,7 +1390,7 @@ bool IRrecv::decodeHaierACYRW02(decode_results* results, uint16_t offset, // Compliance if (strict) { - if (results->state[0] != kHaierAcYrw02Prefix) return false; + if (results->state[0] != kHaierAcYrw02ModelA) return false; if (!IRHaierACYRW02::validChecksum(results->state, nbits / 8)) return false; } @@ -1400,7 +1423,8 @@ bool IRrecv::decodeHaierAC176(decode_results* results, uint16_t offset, // Compliance if (strict) { - if (results->state[0] != kHaierAcYrw02Prefix) return false; + if ((results->state[0] != kHaierAcYrw02ModelA) && + (results->state[0] != kHaierAcYrw02ModelB)) return false; if (!IRHaierAC176::validChecksum(results->state, nbits / 8)) return false; } diff --git a/src/ir_Haier.h b/src/ir_Haier.h index de70ba760..638b38310 100644 --- a/src/ir_Haier.h +++ b/src/ir_Haier.h @@ -139,7 +139,8 @@ const uint8_t kHaierAcYrw02MinTempF = 60; const uint8_t kHaierAcYrw02MaxTempF = 86; const uint8_t kHaierAcYrw02DefTempC = 25; -const uint8_t kHaierAcYrw02Prefix = 0xA6; +const uint8_t kHaierAcYrw02ModelA = 0xA6; +const uint8_t kHaierAcYrw02ModelB = 0x59; const uint8_t kHaierAc176Prefix = 0xB7; const uint8_t kHaierAcYrw02SwingVOff = 0x0; @@ -192,7 +193,7 @@ union HaierAc176Protocol{ uint8_t raw[kHaierAC176StateLength]; ///< The state in native form struct { // Byte 0 - uint8_t Prefix :8; + uint8_t Model :8; // Byte 1 uint8_t SwingV :4; uint8_t Temp :4; // 16C~30C @@ -372,6 +373,9 @@ class IRHaierAC176 { void begin(void); void stateReset(void); + void setModel(const haier_ac176_remote_model_t model); + haier_ac176_remote_model_t getModel(void) const; + void setButton(const uint8_t button); uint8_t getButton(void) const; diff --git a/src/locale/defaults.h b/src/locale/defaults.h index 127e7f470..b6754133f 100644 --- a/src/locale/defaults.h +++ b/src/locale/defaults.h @@ -550,6 +550,12 @@ #ifndef D_STR_YBOFB #define D_STR_YBOFB "YBOFB" #endif // D_STR_YBOFB +#ifndef D_STR_V9014557_A +#define D_STR_V9014557_A "V9014557-A" +#endif // D_STR_V9014557_A +#ifndef D_STR_V9014557_B +#define D_STR_V9014557_B "V9014557-B" +#endif // D_STR_V9014557_B #ifndef D_STR_RLT0541HTA_A #define D_STR_RLT0541HTA_A "R-LT0541-HTA-A" #endif // D_STR_RLT0541HTA_A diff --git a/test/IRac_test.cpp b/test/IRac_test.cpp index 618abfa25..a1e81a775 100644 --- a/test/IRac_test.cpp +++ b/test/IRac_test.cpp @@ -793,23 +793,24 @@ TEST(TestIRac, Haier176) { IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); const char expected[] = - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " - "Fan: 2 (Medium), Turbo: On, Quiet: Off, Swing(V): 1 (Highest), " - "Swing(H): 0 (Middle), Sleep: On, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 23C, Fan: 2 (Medium), Turbo: On, Quiet: Off, " + "Swing(V): 1 (Highest), Swing(H): 0 (Middle), Sleep: On, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off"; ac.begin(); irac.haier176(&ac, - true, // Power - stdAc::opmode_t::kCool, // Mode - true, // Celsius - 23, // Degrees - stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kHigh, // Vertical swing - stdAc::swingh_t::kOff, // Horizontal swing - true, // Turbo - false, // Quiet - true, // Filter - 8 * 60 + 0); // Sleep time + haier_ac176_remote_model_t::V9014557_A, // Model + true, // Power + stdAc::opmode_t::kCool, // Mode + true, // Celsius + 23, // Degrees + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kHigh, // Vertical swing + stdAc::swingh_t::kOff, // Horizontal swing + true, // Turbo + false, // Quiet + true, // Filter + 8 * 60 + 0); // Sleep time ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); @@ -825,9 +826,9 @@ TEST(TestIRac, HaierYrwo2) { IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); char expected[] = - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " - "Fan: 2 (Medium), Turbo: Off, Quiet: On, Swing(V): 1 (Highest), " - "Swing(H): 7 (Auto), Sleep: On, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 23C, Fan: 2 (Medium), Turbo: Off, Quiet: On, " + "Swing(V): 1 (Highest), Swing(H): 7 (Auto), Sleep: On, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off"; ac.begin(); diff --git a/test/ir_Haier_test.cpp b/test/ir_Haier_test.cpp index 6468b3f57..7fa39ebad 100644 --- a/test/ir_Haier_test.cpp +++ b/test/ir_Haier_test.cpp @@ -784,18 +784,18 @@ TEST(TestHaierACYRW02Class, MessageConstuction) { IRHaierACYRW02 ac(kGpioUnused); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 0 (Auto), Temp: 25C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 0 (Off), " - "Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 0 (Auto), Temp: 25C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); ac.setMode(kHaierAcYrw02Cool); ac.setTemp(21); ac.setFan(kHaierAcYrw02FanHigh); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 1 (Cool), Temp: 21C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 0 (Off), " - "Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 4 (Fan), " + "Mode: 1 (Cool), Temp: 21C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); @@ -805,9 +805,9 @@ TEST(TestHaierACYRW02Class, MessageConstuction) { ac.setSleep(true); ac.setTurbo(true); EXPECT_EQ( - "Power: On, Button: 8 (Turbo), Mode: 1 (Cool), Temp: 75F, " - "Fan: 1 (High), Turbo: On, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: On, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 8 (Turbo), " + "Mode: 1 (Cool), Temp: 75F, Fan: 1 (High), Turbo: On, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: On, Health: Off, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } @@ -821,9 +821,9 @@ TEST(TestHaierACYRW02Class, RealStates) { IRHaierACYRW02 ac(kGpioUnused); ac.setRaw(expectedState1); EXPECT_EQ( - "Power: On, Button: 7 (Health), Mode: 4 (Heat), Temp: 30C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 1 (Highest), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 7 (Health), " + "Mode: 4 (Heat), Temp: 30C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 1 (Highest), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); @@ -832,9 +832,9 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x75}; ac.setRaw(expectedState2); EXPECT_EQ( - "Power: Off, Button: 5 (Power), Mode: 4 (Heat), Temp: 30C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 0 (Off), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: Off, Button: 5 (Power), " + "Mode: 4 (Heat), Temp: 30C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); @@ -843,9 +843,9 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2B}; ac.setRaw(expectedState3); EXPECT_EQ( - "Power: On, Button: 1 (Temp Down), Mode: 1 (Cool), Temp: 16C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 1 (Temp Down), " + "Mode: 1 (Cool), Temp: 16C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); @@ -855,9 +855,9 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x20, 0x80, 0x00, 0x00, 0x00, 0x0B, 0xD7}; ac.setRaw(expectedState4); EXPECT_EQ( - "Power: On, Button: 11 (Sleep), Mode: 1 (Cool), Temp: 25C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 12 (Auto), " - "Swing(H): 0 (Middle), Sleep: On, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 11 (Sleep), " + "Mode: 1 (Cool), Temp: 25C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 12 (Auto), Swing(H): 0 (Middle), Sleep: On, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); @@ -867,9 +867,9 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x20, 0x80, 0x00, 0x00, 0x00, 0x04, 0x85}; ac.setRaw(expectedState5); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 1 (Cool), Temp: 25C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 12 (Auto), " - "Swing(H): 0 (Middle), Sleep: On, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 4 (Fan), " + "Mode: 1 (Cool), Temp: 25C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 12 (Auto), Swing(H): 0 (Middle), Sleep: On, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } @@ -1099,9 +1099,9 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) { IRHaierACYRW02 ac(kGpioUnused); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 17C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 17C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } @@ -1238,7 +1238,7 @@ TEST(TestHaierACYRW02Class, toCommon) { ac.setSleep(true); // Now test it. ASSERT_EQ(decode_type_t::HAIER_AC_YRW02, ac.toCommon().protocol); - ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_EQ(1, ac.toCommon().model); ASSERT_TRUE(ac.toCommon().power); ASSERT_TRUE(ac.toCommon().celsius); ASSERT_EQ(20, ac.toCommon().degrees); @@ -1325,9 +1325,9 @@ TEST(TestDecodeHaierAC176, SyntheticDecode) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 6 (UNKNOWN), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 6 (UNKNOWN), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t result, prev; @@ -1367,9 +1367,9 @@ TEST(TestHaierAC176Class, BuildKnownState) { ac.setFan(kHaierAcYrw02FanHigh); EXPECT_TRUE(ac.validChecksum(ac.getRaw())); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 4 (Heat), Temp: 24C, " - "Fan: 1 (High), Turbo: Off, Quiet: Off, Swing(V): 0 (Off), " - "Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Model: 1 (V9014557-A), Power: On, Button: 4 (Fan), " + "Mode: 4 (Heat), Temp: 24C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: On, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); /* Disabled pending: @@ -1459,49 +1459,49 @@ TEST(TestHaierAC176Class, Timers) { ac.setRaw(timer30m); EXPECT_EQ(kHaierAcYrw02OnTimer, ac.getTimerMode()); EXPECT_EQ( - "Power: Off, Button: 16 (Timer), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: Off, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 2 (On), On Timer: 00:30, Off Timer: Off, Lock: Off", ac.toString()); ac.setRaw(timeroff); EXPECT_EQ(kHaierAcYrw02NoTimers, ac.getTimerMode()); EXPECT_EQ( - "Power: On, Button: 16 (Timer), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); ac.setRaw(timeroffthenon); EXPECT_EQ( - "Power: On, Button: 16 (Timer), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 5 (Off-On), On Timer: 08:00, Off Timer: 00:30, Lock: Off", ac.toString()); ac.setTimerMode(kHaierAcYrw02OnThenOffTimer); EXPECT_EQ( - "Power: On, Button: 16 (Timer), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 4 (On-Off), On Timer: 08:00, Off Timer: 00:30, Lock: Off", ac.toString()); ac.setTimerMode(kHaierAcYrw02OffTimer); EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ(30, ac.getOffTimer()); EXPECT_EQ( - "Power: On, Button: 16 (Timer), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 1 (Off), On Timer: Off, Off Timer: 00:30, Lock: Off", ac.toString()); ac.setTimerMode(kHaierAcYrw02NoTimers); EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ(0, ac.getOffTimer()); EXPECT_EQ( - "Power: On, Button: 16 (Timer), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: Off, Quiet: Off, Swing(V): 2 (Middle), " - "Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } From 4a47842e4176f7eaa43ed5b194b951c77dc88f4e Mon Sep 17 00:00:00 2001 From: PtilopsisLeucotis Date: Fri, 12 Nov 2021 16:29:48 +0300 Subject: [PATCH 2/4] [HAIER_AC176/HAIER_AC_YRW02] Additional fixes in A/B unit setting * Update `modelToStr()` * Add comments to `IRac::strToModel()` and `modelToStr()` * Small fix in `IRHaierAC176::toString()` --- src/IRac.cpp | 6 ++++++ src/IRutils.cpp | 1 + src/ir_Haier.cpp | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/IRac.cpp b/src/IRac.cpp index ba70ae017..85cac34a4 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -3315,12 +3315,18 @@ stdAc::swingh_t IRac::strToSwingH(const char *str, /// @param[in] str A Ptr to a C-style string to be converted. /// @param[in] def The enum to return if no conversion was possible. /// @return The equivalent enum. +/// @note After adding a new model you should update modelToStr() too. int16_t IRac::strToModel(const char *str, const int16_t def) { // Gree if (!STRCASECMP(str, kYaw1fStr)) { return gree_ac_remote_model_t::YAW1F; } else if (!STRCASECMP(str, kYbofbStr)) { return gree_ac_remote_model_t::YBOFB; + // Haier models + } else if (!STRCASECMP(str, kV9014557AStr)) { + return haier_ac176_remote_model_t::V9014557_A; + } else if (!STRCASECMP(str, kV9014557BStr)) { + return haier_ac176_remote_model_t::V9014557_B; // HitachiAc1 models } else if (!STRCASECMP(str, kRlt0541htaaStr)) { return hitachi_ac1_remote_model_t::R_LT0541_HTA_A; diff --git a/src/IRutils.cpp b/src/IRutils.cpp index d3e86287d..d3a83c507 100644 --- a/src/IRutils.cpp +++ b/src/IRutils.cpp @@ -586,6 +586,7 @@ namespace irutils { /// @param[in] protocol The IR protocol. /// @param[in] model The model number for that protocol. /// @return The resulting String. + /// @note After adding a new model you should update IRac::strToModel() too. String modelToStr(const decode_type_t protocol, const int16_t model) { switch (protocol) { case decode_type_t::FUJITSU_AC: diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index 78c2f005d..a36fd59af 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -1155,7 +1155,7 @@ String IRHaierAC176::toString(void) const { String result = ""; result.reserve(280); // Reserve some heap for the string to reduce fragging. result += addModelToString(decode_type_t::HAIER_AC176, getModel(), false); - result += addBoolToString(_.Power, kPowerStr, true); + result += addBoolToString(_.Power, kPowerStr); uint8_t cmd = _.Button; result += addIntToString(cmd, kButtonStr); result += kSpaceLBraceStr; From e148a532c788697e23c69448162a5bba23472eed Mon Sep 17 00:00:00 2001 From: PtilopsisLeucotis Date: Sun, 14 Nov 2021 12:33:48 +0300 Subject: [PATCH 3/4] [HAIER_AC176/HAIER_AC_YRW02] Add test for `Model` * Add test for `GetModel()` and `SetModel()` * Add real data test * `SetModel()` now change the `Button` state --- src/ir_Haier.cpp | 1 + test/ir_Haier_test.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index a36fd59af..ef5f208ce 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -637,6 +637,7 @@ haier_ac176_remote_model_t IRHaierAC176::getModel(void) const { /// Set the model of the A/C to emulate. /// @param[in] model The enum of the appropriate model. void IRHaierAC176::setModel(haier_ac176_remote_model_t model) { + _.Button = kHaierAcYrw02ButtonCF; switch (model) { case haier_ac176_remote_model_t::V9014557_B: _.Model = kHaierAcYrw02ModelB; diff --git a/test/ir_Haier_test.cpp b/test/ir_Haier_test.cpp index 7fa39ebad..bf8c9ed3b 100644 --- a/test/ir_Haier_test.cpp +++ b/test/ir_Haier_test.cpp @@ -1505,3 +1505,32 @@ TEST(TestHaierAC176Class, Timers) { "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } + +TEST(TestHaierAC176Class, Models) { + IRHaierAC176 ac(kGpioUnused); + ac.begin(); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_A, ac.getModel()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setModel(haier_ac176_remote_model_t::V9014557_B); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_B, ac.getModel()); + EXPECT_EQ(kHaierAcYrw02ButtonCF, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempDown); + ac.setModel(haier_ac176_remote_model_t::V9014557_A); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_A, ac.getModel()); + EXPECT_EQ(kHaierAcYrw02ButtonCF, ac.getButton()); + + // Real data. + const uint8_t setmodelb[kHaierAC176StateLength] = { + 0x59, 0x82, 0x00, 0x00, 0x40, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x1A, 0x55, 0xB7, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x77}; + ac.setRaw(setmodelb); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_B, ac.getModel()); + EXPECT_EQ( + "Model: 2 (V9014557-B), Power: On, Button: 26 (Celsius/Fahrenheit), " + "Mode: 6 (Fan), Temp: 24C, Fan: 3 (Low), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); +} From 1dc03b85849356fd3f2b43d1dcc6f7d9a7f55e65 Mon Sep 17 00:00:00 2001 From: PtilopsisLeucotis Date: Sun, 14 Nov 2021 13:19:36 +0300 Subject: [PATCH 4/4] [HAIER_AC176/HAIER_AC_YRW02] Rename `kHaierAcYrw02ButtonCF` * Rename `Button` from `kHaierAcYrw02ButtonCF` to `kHaierAcYrw02ButtonCFAB` --- src/ir_Haier.cpp | 8 ++++---- src/ir_Haier.h | 2 +- test/ir_Haier_test.cpp | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index ef5f208ce..5c9f2a36d 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -620,7 +620,7 @@ void IRHaierAC176::setButton(uint8_t button) { case kHaierAcYrw02ButtonTurbo: case kHaierAcYrw02ButtonSleep: case kHaierAcYrw02ButtonLock: - case kHaierAcYrw02ButtonCF: + case kHaierAcYrw02ButtonCFAB: _.Button = button; } } @@ -637,7 +637,7 @@ haier_ac176_remote_model_t IRHaierAC176::getModel(void) const { /// Set the model of the A/C to emulate. /// @param[in] model The enum of the appropriate model. void IRHaierAC176::setModel(haier_ac176_remote_model_t model) { - _.Button = kHaierAcYrw02ButtonCF; + _.Button = kHaierAcYrw02ButtonCFAB; switch (model) { case haier_ac176_remote_model_t::V9014557_B: _.Model = kHaierAcYrw02ModelB; @@ -700,7 +700,7 @@ void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) { else _.Button = kHaierAcYrw02ButtonTempUp; } else { - _.Button = kHaierAcYrw02ButtonCF; + _.Button = kHaierAcYrw02ButtonCFAB; } _.UseFahrenheit = fahrenheit; @@ -1197,7 +1197,7 @@ String IRHaierAC176::toString(void) const { case kHaierAcYrw02ButtonLock: result += kLockStr; break; - case kHaierAcYrw02ButtonCF: + case kHaierAcYrw02ButtonCFAB: result += kCelsiusFahrenheitStr; break; default: diff --git a/src/ir_Haier.h b/src/ir_Haier.h index 638b38310..c1d2d181b 100644 --- a/src/ir_Haier.h +++ b/src/ir_Haier.h @@ -180,7 +180,7 @@ const uint8_t kHaierAcYrw02ButtonTurbo = 0b01000; const uint8_t kHaierAcYrw02ButtonSleep = 0b01011; const uint8_t kHaierAcYrw02ButtonTimer = 0b10000; const uint8_t kHaierAcYrw02ButtonLock = 0b10100; -const uint8_t kHaierAcYrw02ButtonCF = 0b11010; +const uint8_t kHaierAcYrw02ButtonCFAB = 0b11010; const uint8_t kHaierAcYrw02NoTimers = 0b000; const uint8_t kHaierAcYrw02OffTimer = 0b001; diff --git a/test/ir_Haier_test.cpp b/test/ir_Haier_test.cpp index bf8c9ed3b..180015606 100644 --- a/test/ir_Haier_test.cpp +++ b/test/ir_Haier_test.cpp @@ -541,7 +541,7 @@ TEST(TestHaierACYRW02Class, Temperature) { EXPECT_EQ(78, ac.getTemp()); ac.setTemp(24); - EXPECT_EQ(kHaierAcYrw02ButtonCF, ac.getButton()); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); ac.setTemp(0); EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); @@ -1514,12 +1514,12 @@ TEST(TestHaierAC176Class, Models) { ac.setButton(kHaierAcYrw02ButtonTempUp); ac.setModel(haier_ac176_remote_model_t::V9014557_B); EXPECT_EQ(haier_ac176_remote_model_t::V9014557_B, ac.getModel()); - EXPECT_EQ(kHaierAcYrw02ButtonCF, ac.getButton()); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); ac.setButton(kHaierAcYrw02ButtonTempDown); ac.setModel(haier_ac176_remote_model_t::V9014557_A); EXPECT_EQ(haier_ac176_remote_model_t::V9014557_A, ac.getModel()); - EXPECT_EQ(kHaierAcYrw02ButtonCF, ac.getButton()); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); // Real data. const uint8_t setmodelb[kHaierAC176StateLength] = {