diff --git a/src/IRac.cpp b/src/IRac.cpp index 8071b38af..0e3cfb258 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -1170,6 +1170,8 @@ void IRac::haier(IRHaierAC *ac, /// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] quiet Run the device in quiet mode. /// @param[in] clean Turn on the clean mode. +/// @param[in] light Turn on the LED/Display mode. +/// @param[in] prevlight Previous LED/Display mode. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. void IRac::haier160(IRHaierAC160 *ac, const bool on, const stdAc::opmode_t mode, @@ -1177,6 +1179,7 @@ void IRac::haier160(IRHaierAC160 *ac, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool quiet, const bool clean, + const bool light, const bool prevlight, const int16_t sleep) { ac->begin(); // No Model setting available. @@ -1188,13 +1191,14 @@ void IRac::haier160(IRHaierAC160 *ac, // No Horizontal Swing setting available. ac->setQuiet(quiet); ac->setTurbo(turbo); - // No Light setting available. // No Filter setting available. ac->setClean(clean); // No Clean setting available. // No Beep setting available. ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off. ac->setPower(on); + // Light needs to be sent last as the "button" value seems to control it. + ac->setLightToggle(light ^ prevlight); ac->send(); } #endif // SEND_HAIER_AC160 @@ -2762,6 +2766,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { const stdAc::swingv_t prev_swingv = (prev != NULL) ? prev->swingv : stdAc::swingv_t::kOff; #endif // (SEND_LG || SEND_SHARP_AC) +#if (SEND_HAIER_AC160) + const bool prev_light = (prev != NULL) ? prev->light : !send.light; +#endif // (SEND_HAIER_AC160) #if SEND_MIDEA const bool prev_quiet = (prev != NULL) ? prev->quiet : !send.quiet; #endif // SEND_MIDEA @@ -2973,7 +2980,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRHaierAC160 ac(_pin, _inverted, _modulation); haier160(&ac, send.power, send.mode, send.celsius, send.degrees, - send.fanspeed, send.swingv, send.turbo, send.clean, send.sleep); + send.fanspeed, send.swingv, send.turbo, send.clean, + send.light, prev_light, send.sleep); break; } #endif // SEND_HAIER_AC160 @@ -4344,7 +4352,7 @@ namespace IRAcUtils { case decode_type_t::HAIER_AC160: { IRHaierAC160 ac(kGpioUnused); ac.setRaw(decode->state); - *result = ac.toCommon(); + *result = ac.toCommon(prev); break; } #endif // DECODE_HAIER_AC160 diff --git a/src/IRac.h b/src/IRac.h index 52279c456..d9a02c2d3 100644 --- a/src/IRac.h +++ b/src/IRac.h @@ -273,7 +273,8 @@ void electra(IRElectraAc *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 bool turbo, const bool quiet, const bool filter, + const bool turbo, const bool quiet, const bool clean, + const bool light, const bool prevlight, const int16_t sleep = -1); #endif // SEND_HAIER_AC160 #if SEND_HAIER_AC176 diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index de3cad44a..bc919efe9 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -1751,6 +1751,20 @@ void IRHaierAC160::setQuiet(const bool on) { } } +/// Get the value of the current Light toggle setting. +/// @return true, the setting is on. false, the setting is off. +/// @note This setting seems to be controlled just by the button setting. +bool IRHaierAC160::getLightToggle(void) const { + return _.Button == kHaierAc160ButtonLight; +} + +/// Set the Light Toggle setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +/// @note This setting seems to be controlled just by the button setting. +void IRHaierAC160::setLightToggle(const bool on) { + _.Button = on ? kHaierAc160ButtonLight : kHaierAcYrw02ButtonPower; +} + /// Get the current fan speed setting. /// @return The current fan speed. uint8_t IRHaierAC160::getFan(void) const { return _.Fan; } @@ -1970,9 +1984,19 @@ stdAc::swingv_t IRHaierAC160::toCommonSwingV(const uint8_t pos) { } /// Convert the current internal state into its stdAc::state_t equivalent. +/// @param[in] prev Ptr to the previous state if required. /// @return The stdAc equivalent of the native settings. -stdAc::state_t IRHaierAC160::toCommon(void) const { +stdAc::state_t IRHaierAC160::toCommon(const stdAc::state_t *prev) const { stdAc::state_t result{}; + // Start with the previous state if given it. + if (prev != NULL) { + result = *prev; + } else { + // Set defaults for non-zero values that are not implicitly set for when + // there is no previous state. + // e.g. Any setting that toggles should probably go here. + result.light = false; + } result.protocol = decode_type_t::HAIER_AC160; result.power = _.Power; result.mode = toCommonMode(_.Mode); @@ -1985,11 +2009,11 @@ stdAc::state_t IRHaierAC160::toCommon(void) const { result.turbo = _.Turbo; result.quiet = _.Quiet; result.clean = _.Clean && _.Clean2; + result.light ^= getLightToggle(); // Not supported. result.filter = false; result.model = -1; result.econo = false; - result.light = false; result.beep = true; result.clock = -1; return result; @@ -2044,6 +2068,9 @@ String IRHaierAC160::toString(void) const { case kHaierAc160ButtonClean: result += kCleanStr; break; + case kHaierAc160ButtonLight: + result += kLightStr; + break; case kHaierAcYrw02ButtonCFAB: result += kCelsiusFahrenheitStr; break; diff --git a/src/ir_Haier.h b/src/ir_Haier.h index cb46c1582..9ea205c5c 100644 --- a/src/ir_Haier.h +++ b/src/ir_Haier.h @@ -194,6 +194,7 @@ const uint8_t kHaierAcYrw02ButtonTurbo = 0b01000; const uint8_t kHaierAcYrw02ButtonSleep = 0b01011; const uint8_t kHaierAcYrw02ButtonTimer = 0b10000; const uint8_t kHaierAcYrw02ButtonLock = 0b10100; +const uint8_t kHaierAc160ButtonLight = 0b10101; const uint8_t kHaierAc160ButtonClean = 0b11001; const uint8_t kHaierAcYrw02ButtonCFAB = 0b11010; @@ -596,6 +597,8 @@ class IRHaierAC160 { void setSleep(const bool on); bool getClean(void) const; void setClean(const bool on); + bool getLightToggle(void) const; + void setLightToggle(const bool on); bool getTurbo(void) const; void setTurbo(const bool on); @@ -627,7 +630,7 @@ class IRHaierAC160 { static stdAc::swingv_t toCommonSwingV(const uint8_t pos); static bool toCommonTurbo(const uint8_t speed); static bool toCommonQuiet(const uint8_t speed); - stdAc::state_t toCommon(void) const; + stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const; String toString(void) const; #ifndef UNIT_TEST diff --git a/test/IRac_test.cpp b/test/IRac_test.cpp index 9e09c6a8b..ce89d0d23 100644 --- a/test/IRac_test.cpp +++ b/test/IRac_test.cpp @@ -840,6 +840,8 @@ TEST(TestIRac, Haier160) { true, // Turbo false, // Quiet true, // Clean + true, // Light + true, // Light (prev) 8 * 60 + 0); // Sleep time ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); diff --git a/test/ir_Haier_test.cpp b/test/ir_Haier_test.cpp index 911291349..dcc60961a 100644 --- a/test/ir_Haier_test.cpp +++ b/test/ir_Haier_test.cpp @@ -1946,3 +1946,34 @@ TEST(TestHaierAC160Class, SwingV) { EXPECT_EQ(kHaierAc160SwingVLow, ac.getSwingV()); EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); } + +TEST(TestHaierAC160Class, Light) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setLightToggle(true); + EXPECT_TRUE(ac.getLightToggle()); + EXPECT_EQ(kHaierAc160ButtonLight, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setLightToggle(false); + EXPECT_FALSE(ac.getLightToggle()); + EXPECT_NE(kHaierAc160ButtonLight, ac.getButton()); + + ac.setLightToggle(true); + EXPECT_TRUE(ac.getLightToggle()); + EXPECT_EQ(kHaierAc160ButtonLight, ac.getButton()); + + const uint8_t light_press[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x15, 0x27, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15}; + ac.setRaw(light_press); + EXPECT_TRUE(ac.getLightToggle()); + EXPECT_EQ(kHaierAc160ButtonLight, ac.getButton()); + EXPECT_EQ( + "Power: On, Button: 21 (Light), Mode: 1 (Cool), Temp: 26C, " + "Fan: 3 (Low), Turbo: Off, Quiet: Off, Swing(V): 12 (Auto), " + "Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), " + "On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); +}