diff --git a/src/IRac.cpp b/src/IRac.cpp index cff285471..78bf294c3 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -1112,6 +1112,7 @@ void IRac::haier(IRHaierAC *ac, /// @param[in, out] ac A Ptr to an IRHaierAC176 object 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. /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. @@ -1122,12 +1123,15 @@ void IRac::haier(IRHaierAC *ac, /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. void IRac::haier176(IRHaierAC176 *ac, const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + 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) { ac->begin(); ac->setMode(ac->convertMode(mode)); + ac->setUseFahrenheit(!celsius); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); ac->setSwingV(ac->convertSwingV(swingv)); @@ -1149,6 +1153,7 @@ void IRac::haier176(IRHaierAC176 *ac, /// @param[in, out] ac A Ptr to an IRHaierACYRW02 object 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. /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. @@ -1159,13 +1164,15 @@ void IRac::haier176(IRHaierAC176 *ac, /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. void IRac::haierYrwo2(IRHaierACYRW02 *ac, const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, + 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) { ac->begin(); ac->setMode(ac->convertMode(mode)); + ac->setUseFahrenheit(!celsius); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); ac->setSwingV(ac->convertSwingV(swingv)); @@ -2797,8 +2804,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, degC, send.fanspeed, send.swingv, - send.swingh, send.turbo, send.filter, send.sleep); + haier176(&ac, 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 @@ -2806,8 +2814,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HAIER_AC_YRW02: { IRHaierACYRW02 ac(_pin, _inverted, _modulation); - haierYrwo2(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, - send.swingh, send.turbo, send.filter, send.sleep); + haierYrwo2(&ac, send.power, send.mode, send.celsius, send.degrees, + send.fanspeed, send.swingv, send.swingh, send.turbo, + send.filter, send.sleep); break; } #endif // SEND_HAIER_AC_YRW02 diff --git a/src/IRac.h b/src/IRac.h index c0ae4921f..2696e3809 100644 --- a/src/IRac.h +++ b/src/IRac.h @@ -261,17 +261,19 @@ void electra(IRElectraAc *ac, #if SEND_HAIER_AC176 void haier176(IRHaierAC176 *ac, const bool on, const stdAc::opmode_t mode, - 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 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 void haierYrwo2(IRHaierACYRW02 *ac, const bool on, const stdAc::opmode_t mode, - 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 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_AC_YRW02 #if SEND_HITACHI_AC diff --git a/src/ir_Haier.cpp b/src/ir_Haier.cpp index 20fffa229..cb5c2f88a 100644 --- a/src/ir_Haier.cpp +++ b/src/ir_Haier.cpp @@ -584,7 +584,7 @@ void IRHaierAC176::stateReset(void) { std::memset(_.raw, 0, sizeof _.raw); _.Prefix = kHaierAcYrw02Prefix; _.Prefix2 = kHaierAc176Prefix; - _.Temp = kHaierAcDefTemp - kHaierAcMinTemp; + _.Temp = kHaierAcYrw02DefTempC - kHaierAcYrw02MinTempC; _.Health = true; setFan(kHaierAcYrw02FanAuto); _.Power = true; @@ -619,6 +619,7 @@ void IRHaierAC176::setButton(uint8_t button) { case kHaierAcYrw02ButtonTurbo: case kHaierAcYrw02ButtonSleep: case kHaierAcYrw02ButtonLock: + case kHaierAcYrw02ButtonCF: _.Button = button; } } @@ -654,27 +655,96 @@ void IRHaierAC176::setMode(uint8_t mode) { /// @return The current operating mode setting. uint8_t IRHaierAC176::getMode(void) const { return _.Mode; } -/// Set the temperature. -/// @param[in] celsius The temperature in degrees celsius. -void IRHaierAC176::setTemp(const uint8_t celsius) { - uint8_t temp = celsius; - if (temp < kHaierAcMinTemp) - temp = kHaierAcMinTemp; - else if (temp > kHaierAcMaxTemp) - temp = kHaierAcMaxTemp; +/// Set the default temperature units to use. +/// @param[in] on Use Fahrenheit as the units. +/// true is Fahrenheit, false is Celsius. +void IRHaierAC176::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; } + +/// Get the default temperature units in use. +/// @return true is Fahrenheit, false is Celsius. +bool IRHaierAC176::getUseFahrenheit(void) const { return _.UseFahrenheit; } +/// Set the temperature. +/// @param[in] degree The temperature in degrees. +/// @param[in] fahrenheit Use units of Fahrenheit and set that as units used. +void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) { uint8_t old_temp = getTemp(); - if (old_temp == temp) return; - if (old_temp > temp) - _.Button = kHaierAcYrw02ButtonTempDown; - else - _.Button = kHaierAcYrw02ButtonTempUp; - _.Temp = temp - kHaierAcMinTemp; + if (old_temp == degree) return; + + if (_.UseFahrenheit == fahrenheit) { + if (old_temp > degree) + _.Button = kHaierAcYrw02ButtonTempDown; + else + _.Button = kHaierAcYrw02ButtonTempUp; + } else { + _.Button = kHaierAcYrw02ButtonCF; + } + _.UseFahrenheit = fahrenheit; + + uint8_t temp = degree; + if (fahrenheit) { + if (temp < kHaierAcYrw02MinTempF) + temp = kHaierAcYrw02MinTempF; + else if (temp > kHaierAcYrw02MaxTempF) + temp = kHaierAcYrw02MaxTempF; + if (degree >= 77) { temp++; } + if (degree >= 79) { temp++; } + // See at IRHaierAC176::getTemp() comments for clarification + _.ExtraDegreeF = temp % 2; + _.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1; + } else { + if (temp < kHaierAcYrw02MinTempC) + temp = kHaierAcYrw02MinTempC; + else if (temp > kHaierAcYrw02MaxTempC) + temp = kHaierAcYrw02MaxTempC; + _.Temp = temp - kHaierAcYrw02MinTempC; + } } /// Get the current temperature setting. /// @return The current setting for temp. in degrees celsius. -uint8_t IRHaierAC176::getTemp(void) const { return _.Temp + kHaierAcMinTemp; } +uint8_t IRHaierAC176::getTemp(void) const { + if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; } + uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF; + // The way of coding the temperature in degree Fahrenheit is + // kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example + // Temp = 0b0011, ExtraDegreeF = 0b1, temperature is 60 + 3*2 + 1 = 67F + // But around 78F there is unconsistency, see table below + // + // | Fahrenheit | Temp | ExtraDegreeF | + // | 60F | 0b0000 | 0b0 | + // | 61F | 0b0000 | 0b1 | + // | 62F | 0b0001 | 0b0 | + // | 63F | 0b0001 | 0b1 | + // | 64F | 0b0010 | 0b0 | + // | 65F | 0b0010 | 0b1 | + // | 66F | 0b0011 | 0b0 | + // | 67F | 0b0011 | 0b1 | + // | 68F | 0b0100 | 0b0 | + // | 69F | 0b0100 | 0b1 | + // | 70F | 0b0101 | 0b0 | + // | 71F | 0b0101 | 0b1 | + // | 72F | 0b0110 | 0b0 | + // | 73F | 0b0110 | 0b1 | + // | 74F | 0b0111 | 0b0 | + // | 75F | 0b0111 | 0b1 | + // | 76F | 0b1000 | 0b0 | + // | Not Used | 0b1000 | 0b1 | + // | 77F | 0b1001 | 0b0 | + // | Not Used | 0b1001 | 0b1 | + // | 78F | 0b1010 | 0b0 | + // | 79F | 0b1010 | 0b1 | + // | 80F | 0b1011 | 0b0 | + // | 81F | 0b1011 | 0b1 | + // | 82F | 0b1100 | 0b0 | + // | 83F | 0b1100 | 0b1 | + // | 84F | 0b1101 | 0b0 | + // | 86F | 0b1110 | 0b0 | + // | 85F | 0b1101 | 0b1 | + if (degree >= 77) { degree--; } + if (degree >= 79) { degree--; } + return degree; +} /// Set the Health (filter) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. @@ -1038,7 +1108,7 @@ stdAc::state_t IRHaierAC176::toCommon(void) const { result.model = -1; // No models used. result.power = _.Power; result.mode = toCommonMode(_.Mode); - result.celsius = true; + result.celsius = !_.UseFahrenheit; result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(_.Fan); result.swingv = toCommonSwingV(_.SwingV); @@ -1102,6 +1172,9 @@ String IRHaierAC176::toString(void) const { case kHaierAcYrw02ButtonLock: result += kLockStr; break; + case kHaierAcYrw02ButtonCF: + result += kCelsiusFahrenheitStr; + break; default: result += kUnknownStr; } @@ -1109,7 +1182,7 @@ String IRHaierAC176::toString(void) const { result += addModeToString(_.Mode, kHaierAcYrw02Auto, kHaierAcYrw02Cool, kHaierAcYrw02Heat, kHaierAcYrw02Dry, kHaierAcYrw02Fan); - result += addTempToString(getTemp()); + result += addTempToString(getTemp(), !_.UseFahrenheit); result += addFanToString(_.Fan, kHaierAcYrw02FanHigh, kHaierAcYrw02FanLow, kHaierAcYrw02FanAuto, kHaierAcYrw02FanAuto, kHaierAcYrw02FanMed); diff --git a/src/ir_Haier.h b/src/ir_Haier.h index 1af16f047..de70ba760 100644 --- a/src/ir_Haier.h +++ b/src/ir_Haier.h @@ -133,6 +133,12 @@ const uint8_t kHaierAcSleepBit = 0b01000000; #define HAIER_AC_FAN_MED kHaierAcFanMed #define HAIER_AC_FAN_HIGH kHaierAcFanHigh +const uint8_t kHaierAcYrw02MinTempC = 16; +const uint8_t kHaierAcYrw02MaxTempC = 30; +const uint8_t kHaierAcYrw02MinTempF = 60; +const uint8_t kHaierAcYrw02MaxTempF = 86; +const uint8_t kHaierAcYrw02DefTempC = 25; + const uint8_t kHaierAcYrw02Prefix = 0xA6; const uint8_t kHaierAc176Prefix = 0xB7; @@ -173,6 +179,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 kHaierAcYrw02NoTimers = 0b000; const uint8_t kHaierAcYrw02OffTimer = 0b001; @@ -218,7 +225,10 @@ union HaierAc176Protocol{ // Byte 9 uint8_t :8; // Byte 10 - uint8_t :8; + uint8_t ExtraDegreeF :1; + uint8_t :4; + uint8_t UseFahrenheit:1; + uint8_t :2; // Byte 11 uint8_t :8; // Byte 12 @@ -365,7 +375,9 @@ class IRHaierAC176 { void setButton(const uint8_t button); uint8_t getButton(void) const; - void setTemp(const uint8_t temp); + void setUseFahrenheit(const bool on); + bool getUseFahrenheit(void) const; + void setTemp(const uint8_t temp, const bool fahrenheit = false); uint8_t getTemp(void) const; void setFan(const uint8_t speed); diff --git a/test/IRac_test.cpp b/test/IRac_test.cpp index 5abec2367..2b74d6970 100644 --- a/test/IRac_test.cpp +++ b/test/IRac_test.cpp @@ -798,7 +798,8 @@ TEST(TestIRac, Haier176) { irac.haier176(&ac, true, // Power stdAc::opmode_t::kCool, // Mode - 23, // Celsius + true, // Celsius + 23, // Degrees stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kHigh, // Vertical swing stdAc::swingh_t::kOff, // Horizontal swing @@ -830,7 +831,8 @@ TEST(TestIRac, HaierYrwo2) { irac.haierYrwo2(&ac, true, // Power stdAc::opmode_t::kCool, // Mode - 23, // Celsius + true, // Celsius + 23, // Degrees stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kHigh, // Vertical swing stdAc::swingh_t::kAuto, // Vertical swing diff --git a/test/ir_Haier_test.cpp b/test/ir_Haier_test.cpp index 841eb8262..6468b3f57 100644 --- a/test/ir_Haier_test.cpp +++ b/test/ir_Haier_test.cpp @@ -476,24 +476,24 @@ TEST(TestHaierACYRW02Class, Temperature) { IRHaierACYRW02 ac(kGpioUnused); ac.begin(); - ac.setTemp(kHaierAcMinTemp); - EXPECT_EQ(kHaierAcMinTemp, ac.getTemp()); + ac.setTemp(kHaierAcYrw02MinTempC); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); ac.setButton(kHaierAcYrw02ButtonPower); - ac.setTemp(kHaierAcMinTemp + 1); - EXPECT_EQ(kHaierAcMinTemp + 1, ac.getTemp()); + ac.setTemp(kHaierAcYrw02MinTempC + 1); + EXPECT_EQ(kHaierAcYrw02MinTempC + 1, ac.getTemp()); EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); - ac.setTemp(kHaierAcMaxTemp); - EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + ac.setTemp(kHaierAcYrw02MaxTempC); + EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp()); EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); - ac.setTemp(kHaierAcMinTemp - 1); - EXPECT_EQ(kHaierAcMinTemp, ac.getTemp()); + ac.setTemp(kHaierAcYrw02MinTempC - 1); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); - ac.setTemp(kHaierAcMaxTemp + 1); - EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + ac.setTemp(kHaierAcYrw02MaxTempC + 1); + EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp()); EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); ac.setTemp(23); @@ -504,8 +504,47 @@ TEST(TestHaierACYRW02Class, Temperature) { EXPECT_EQ(23, ac.getTemp()); EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + ac.setTemp(kHaierAcYrw02MinTempF, true); + EXPECT_EQ(kHaierAcYrw02MinTempF, ac.getTemp()); + + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(kHaierAcYrw02MinTempF + 1, true); + EXPECT_EQ(kHaierAcYrw02MinTempF + 1, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempF, true); + EXPECT_EQ(kHaierAcYrw02MaxTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MinTempF - 1, true); + EXPECT_EQ(kHaierAcYrw02MinTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempF + 1, true); + EXPECT_EQ(kHaierAcYrw02MaxTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(66, true); + EXPECT_EQ(66, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(66, true); + EXPECT_EQ(66, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + // Test specific cases for converting to Fahrenheit + ac.setTemp(76, true); + EXPECT_EQ(76, ac.getTemp()); + ac.setTemp(77, true); + EXPECT_EQ(77, ac.getTemp()); + ac.setTemp(78, true); + EXPECT_EQ(78, ac.getTemp()); + + ac.setTemp(24); + EXPECT_EQ(kHaierAcYrw02ButtonCF, ac.getButton()); + ac.setTemp(0); - EXPECT_EQ(kHaierAcMinTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); ac.setTemp(255); @@ -760,12 +799,13 @@ TEST(TestHaierACYRW02Class, MessageConstuction) { "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); + ac.setTemp(75, true); ac.setSwingV(kHaierAcYrw02SwingVMiddle); ac.setHealth(false); ac.setSleep(true); ac.setTurbo(true); EXPECT_EQ( - "Power: On, Button: 8 (Turbo), Mode: 1 (Cool), Temp: 21C, " + "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",