mirror of
https://github.com/crankyoldgit/IRremoteESP8266.git
synced 2026-01-12 00:05:10 +08:00
HAIER_AC160: Experimental detail support. (#1852)
* This is basically a cut & paste of the `IRHaierAC176` class.
- Without some features. e.g. SwingH
- Modified values for SwingV
* Rough unit test coverage for new code.
- Needs more real data to confirm etc.
* Add in support required for `IRac` class to work with this protocol.
* Add Light support
- Report the button press code.
- Make a guess at how the setting works.
- i.e. The button code toggles the light on and off.
- Adjust `toCommon()` to handle previous state.
- Handle the light toggles appropriately.
- Add a unit test case.
* Add AuxHeating setting.
* Add support for setting/getting Health/Filter status.
Fixes #1804
This commit is contained in:
77
src/IRac.cpp
77
src/IRac.cpp
@@ -219,6 +219,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
|
||||
#if SEND_HAIER_AC
|
||||
case decode_type_t::HAIER_AC:
|
||||
#endif
|
||||
#if SEND_HAIER_AC160
|
||||
case decode_type_t::HAIER_AC160:
|
||||
#endif // SEND_HAIER_AC160
|
||||
#if SEND_HAIER_AC176
|
||||
case decode_type_t::HAIER_AC176:
|
||||
#endif // SEND_HAIER_AC176
|
||||
@@ -1200,6 +1203,52 @@ void IRac::haier(IRHaierAC *ac,
|
||||
}
|
||||
#endif // SEND_HAIER_AC
|
||||
|
||||
#if SEND_HAIER_AC160
|
||||
/// Send a Haier 160 bit A/C message with the supplied settings.
|
||||
/// @param[in, out] ac A Ptr to an IRHaierAC160 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.
|
||||
/// @param[in] turbo Run the device in turbo/powerful mode.
|
||||
/// @param[in] quiet Run the device in quiet mode.
|
||||
/// @param[in] filter Turn on the (ion/pollen/etc) filter 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,
|
||||
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 clean, const bool light, const bool prevlight,
|
||||
const int16_t sleep) {
|
||||
ac->begin();
|
||||
// No Model setting available.
|
||||
ac->setMode(ac->convertMode(mode));
|
||||
ac->setUseFahrenheit(!celsius);
|
||||
ac->setTemp(degrees);
|
||||
ac->setFan(ac->convertFan(fan));
|
||||
ac->setSwingV(ac->convertSwingV(swingv));
|
||||
// No Horizontal Swing setting available.
|
||||
ac->setQuiet(quiet);
|
||||
ac->setTurbo(turbo);
|
||||
ac->setHealth(filter);
|
||||
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
|
||||
|
||||
#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.
|
||||
@@ -2764,6 +2813,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
|
||||
@@ -2978,6 +3030,16 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
|
||||
break;
|
||||
}
|
||||
#endif // SEND_HAIER_AC
|
||||
#if SEND_HAIER_AC160
|
||||
case HAIER_AC160:
|
||||
{
|
||||
IRHaierAC160 ac(_pin, _inverted, _modulation);
|
||||
haier160(&ac, send.power, send.mode, send.celsius, send.degrees,
|
||||
send.fanspeed, send.swingv, send.turbo, send.filter, send.clean,
|
||||
send.light, prev_light, send.sleep);
|
||||
break;
|
||||
}
|
||||
#endif // SEND_HAIER_AC160
|
||||
#if SEND_HAIER_AC176
|
||||
case HAIER_AC176:
|
||||
{
|
||||
@@ -3876,6 +3938,13 @@ namespace IRAcUtils {
|
||||
return ac.toString();
|
||||
}
|
||||
#endif // DECODE_HAIER_AC
|
||||
#if DECODE_HAIER_AC160
|
||||
case decode_type_t::HAIER_AC160: {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.setRaw(result->state);
|
||||
return ac.toString();
|
||||
}
|
||||
#endif // DECODE_HAIER_AC160
|
||||
#if DECODE_HAIER_AC176
|
||||
case decode_type_t::HAIER_AC176: {
|
||||
IRHaierAC176 ac(kGpioUnused);
|
||||
@@ -4351,6 +4420,14 @@ namespace IRAcUtils {
|
||||
break;
|
||||
}
|
||||
#endif // DECODE_HAIER_AC
|
||||
#if DECODE_HAIER_AC160
|
||||
case decode_type_t::HAIER_AC160: {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.setRaw(decode->state);
|
||||
*result = ac.toCommon(prev);
|
||||
break;
|
||||
}
|
||||
#endif // DECODE_HAIER_AC160
|
||||
#if DECODE_HAIER_AC176
|
||||
case decode_type_t::HAIER_AC176: {
|
||||
IRHaierAC176 ac(kGpioUnused);
|
||||
|
||||
@@ -275,6 +275,15 @@ void electra(IRElectraAc *ac,
|
||||
const bool filter, const int16_t sleep = -1,
|
||||
const int16_t clock = -1);
|
||||
#endif // SEND_HAIER_AC
|
||||
#if SEND_HAIER_AC160
|
||||
void haier160(IRHaierAC160 *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 clean, const bool light, const bool prevlight,
|
||||
const int16_t sleep = -1);
|
||||
#endif // SEND_HAIER_AC160
|
||||
#if SEND_HAIER_AC176
|
||||
void haier176(IRHaierAC176 *ac,
|
||||
const haier_ac176_remote_model_t model, const bool on,
|
||||
|
||||
686
src/ir_Haier.cpp
686
src/ir_Haier.cpp
@@ -1481,3 +1481,689 @@ bool IRrecv::decodeHaierAC160(decode_results* results, uint16_t offset,
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_HAIER_AC160
|
||||
|
||||
|
||||
/// Class constructor
|
||||
/// @param[in] pin GPIO to be used when sending.
|
||||
/// @param[in] inverted Is the output signal to be inverted?
|
||||
/// @param[in] use_modulation Is frequency modulation to be used?
|
||||
IRHaierAC160::IRHaierAC160(const uint16_t pin, const bool inverted,
|
||||
const bool use_modulation)
|
||||
: _irsend(pin, inverted, use_modulation) { stateReset(); }
|
||||
|
||||
/// Set up hardware to be able to send a message.
|
||||
void IRHaierAC160::begin(void) { _irsend.begin(); }
|
||||
|
||||
#if SEND_HAIER_AC160
|
||||
/// Send the current internal state as an IR message.
|
||||
/// @param[in] repeat Nr. of times the message will be repeated.
|
||||
void IRHaierAC160::send(const uint16_t repeat) {
|
||||
_irsend.sendHaierAC160(getRaw(), kHaierAC160StateLength, repeat);
|
||||
}
|
||||
#endif // SEND_HAIER_AC160
|
||||
|
||||
/// Calculate and set the checksum values for the internal state.
|
||||
void IRHaierAC160::checksum(void) {
|
||||
_.Sum = sumBytes(_.raw, kHaierACYRW02StateLength - 1);
|
||||
_.Sum2 = sumBytes(_.raw + kHaierACYRW02StateLength,
|
||||
kHaierAC160StateLength - kHaierACYRW02StateLength - 1);
|
||||
}
|
||||
|
||||
/// Reset the internal state to a fixed known good state.
|
||||
void IRHaierAC160::stateReset(void) {
|
||||
std::memset(_.raw, 0, sizeof _.raw);
|
||||
_.Model = kHaierAcYrw02ModelA;
|
||||
_.Prefix = kHaierAc160Prefix;
|
||||
_.Temp = kHaierAcYrw02DefTempC - kHaierAcYrw02MinTempC;
|
||||
setClean(false);
|
||||
setFan(kHaierAcYrw02FanAuto);
|
||||
_.Power = true;
|
||||
_.Button = kHaierAcYrw02ButtonPower;
|
||||
}
|
||||
|
||||
/// Get a PTR to the internal state/code for this protocol.
|
||||
/// @return PTR to a code for this protocol based on the current internal state.
|
||||
uint8_t* IRHaierAC160::getRaw(void) {
|
||||
checksum();
|
||||
return _.raw;
|
||||
}
|
||||
|
||||
/// Set the internal state from a valid code for this protocol.
|
||||
/// @param[in] new_code A valid code for this protocol.
|
||||
void IRHaierAC160::setRaw(const uint8_t new_code[]) {
|
||||
memcpy(_.raw, new_code, kHaierAC160StateLength);
|
||||
}
|
||||
|
||||
/// Set the Button/Command setting of the A/C.
|
||||
/// @param[in] button The value of the button/command that was pressed.
|
||||
void IRHaierAC160::setButton(uint8_t button) {
|
||||
switch (button) {
|
||||
case kHaierAcYrw02ButtonTempUp:
|
||||
case kHaierAcYrw02ButtonTempDown:
|
||||
case kHaierAcYrw02ButtonSwingV:
|
||||
case kHaierAcYrw02ButtonSwingH:
|
||||
case kHaierAcYrw02ButtonFan:
|
||||
case kHaierAcYrw02ButtonPower:
|
||||
case kHaierAcYrw02ButtonMode:
|
||||
case kHaierAcYrw02ButtonHealth:
|
||||
case kHaierAcYrw02ButtonTurbo:
|
||||
case kHaierAcYrw02ButtonSleep:
|
||||
case kHaierAcYrw02ButtonLock:
|
||||
case kHaierAc160ButtonClean:
|
||||
case kHaierAcYrw02ButtonCFAB:
|
||||
_.Button = button;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Button/Command setting of the A/C.
|
||||
/// @return The value of the button/command that was pressed.
|
||||
uint8_t IRHaierAC160::getButton(void) const { return _.Button; }
|
||||
|
||||
/// Set the operating mode of the A/C.
|
||||
/// @param[in] mode The desired operating mode.
|
||||
void IRHaierAC160::setMode(uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kHaierAcYrw02Auto:
|
||||
case kHaierAcYrw02Dry:
|
||||
case kHaierAcYrw02Fan:
|
||||
// Turbo & Quiet is only available in Cool/Heat mode.
|
||||
_.Turbo = false;
|
||||
_.Quiet = false;
|
||||
// FALL-THRU
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Heat:
|
||||
_.Button = kHaierAcYrw02ButtonMode;
|
||||
_.Mode = mode;
|
||||
break;
|
||||
default:
|
||||
setMode(kHaierAcYrw02Auto); // Unexpected, default to auto mode.
|
||||
}
|
||||
_.AuxHeating = (_.Mode == kHaierAcYrw02Heat); // Set only if heat mode.
|
||||
}
|
||||
|
||||
/// Get the operating mode setting of the A/C.
|
||||
/// @return The current operating mode setting.
|
||||
uint8_t IRHaierAC160::getMode(void) const { return _.Mode; }
|
||||
|
||||
/// Set the default temperature units to use.
|
||||
/// @param[in] on Use Fahrenheit as the units.
|
||||
/// true is Fahrenheit, false is Celsius.
|
||||
void IRHaierAC160::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; }
|
||||
|
||||
/// Get the default temperature units in use.
|
||||
/// @return true is Fahrenheit, false is Celsius.
|
||||
bool IRHaierAC160::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 IRHaierAC160::setTemp(const uint8_t degree, const bool fahrenheit) {
|
||||
uint8_t old_temp = getTemp();
|
||||
if (old_temp == degree) return;
|
||||
|
||||
if (_.UseFahrenheit == fahrenheit) {
|
||||
if (old_temp > degree)
|
||||
_.Button = kHaierAcYrw02ButtonTempDown;
|
||||
else
|
||||
_.Button = kHaierAcYrw02ButtonTempUp;
|
||||
} else {
|
||||
_.Button = kHaierAcYrw02ButtonCFAB;
|
||||
}
|
||||
_.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 IRHaierAC160::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.
|
||||
/// The unit of temperature is specified by UseFahrenheit value.
|
||||
/// @return The current setting for temperature.
|
||||
uint8_t IRHaierAC160::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 Clean setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC160::setClean(const bool on) {
|
||||
_.Button = kHaierAc160ButtonClean;
|
||||
_.Clean = on;
|
||||
_.Clean2 = on;
|
||||
}
|
||||
|
||||
/// Get the Clean setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC160::getClean(void) const { return _.Clean && _.Clean2; }
|
||||
|
||||
/// Get the value of the current power setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC160::getPower(void) const { return _.Power; }
|
||||
|
||||
/// Change the power setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC160::setPower(const bool on) {
|
||||
_.Button = kHaierAcYrw02ButtonPower;
|
||||
_.Power = on;
|
||||
}
|
||||
|
||||
/// Change the power setting to On.
|
||||
void IRHaierAC160::on(void) { setPower(true); }
|
||||
|
||||
/// Change the power setting to Off.
|
||||
void IRHaierAC160::off(void) { setPower(false); }
|
||||
|
||||
/// Get the Sleep setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC160::getSleep(void) const { return _.Sleep; }
|
||||
|
||||
/// Set the Sleep setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC160::setSleep(const bool on) {
|
||||
_.Button = kHaierAcYrw02ButtonSleep;
|
||||
_.Sleep = on;
|
||||
}
|
||||
|
||||
/// Get the Turbo setting of the A/C.
|
||||
/// @return The current turbo setting.
|
||||
bool IRHaierAC160::getTurbo(void) const { return _.Turbo; }
|
||||
|
||||
/// Set the Turbo setting of the A/C.
|
||||
/// @param[in] on The desired turbo setting.
|
||||
/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode
|
||||
void IRHaierAC160::setTurbo(const bool on) {
|
||||
switch (getMode()) {
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Heat:
|
||||
_.Turbo = on;
|
||||
_.Button = kHaierAcYrw02ButtonTurbo;
|
||||
if (on) _.Quiet = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Quiet setting of the A/C.
|
||||
/// @return The current Quiet setting.
|
||||
bool IRHaierAC160::getQuiet(void) const { return _.Quiet; }
|
||||
|
||||
/// Set the Quiet setting of the A/C.
|
||||
/// @param[in] on The desired Quiet setting.
|
||||
/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode
|
||||
void IRHaierAC160::setQuiet(const bool on) {
|
||||
switch (getMode()) {
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Heat:
|
||||
_.Quiet = on;
|
||||
_.Button = kHaierAcYrw02ButtonTurbo;
|
||||
if (on) _.Turbo = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of the Aux Heating setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC160::getAuxHeating(void) const { return _.AuxHeating; }
|
||||
|
||||
/// Change the Aux Heating setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC160::setAuxHeating(const bool on) {
|
||||
_.Button = kHaierAc160ButtonAuxHeating;
|
||||
_.AuxHeating = 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; }
|
||||
|
||||
/// Set the speed of the fan.
|
||||
/// @param[in] speed The desired setting.
|
||||
void IRHaierAC160::setFan(uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kHaierAcYrw02FanLow:
|
||||
case kHaierAcYrw02FanMed:
|
||||
case kHaierAcYrw02FanHigh:
|
||||
case kHaierAcYrw02FanAuto:
|
||||
_.Fan = speed;
|
||||
_.Fan2 = (speed == kHaierAcYrw02FanAuto) ? 0 : speed;
|
||||
_.Button = kHaierAcYrw02ButtonFan;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Health (filter) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC160::setHealth(const bool on) {
|
||||
_.Button = kHaierAcYrw02ButtonHealth;
|
||||
_.Health = on;
|
||||
}
|
||||
|
||||
/// Get the Health (filter) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC160::getHealth(void) const { return _.Health; }
|
||||
|
||||
/// Get the Vertical Swing position setting of the A/C.
|
||||
/// @return The native position/mode.
|
||||
uint8_t IRHaierAC160::getSwingV(void) const { return _.SwingV; }
|
||||
|
||||
/// Set the Vertical Swing mode of the A/C.
|
||||
/// @param[in] pos The position/mode to set the vanes to.
|
||||
void IRHaierAC160::setSwingV(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kHaierAc160SwingVOff:
|
||||
case kHaierAc160SwingVAuto:
|
||||
case kHaierAc160SwingVTop:
|
||||
case kHaierAc160SwingVHighest:
|
||||
case kHaierAc160SwingVHigh:
|
||||
case kHaierAc160SwingVMiddle:
|
||||
case kHaierAc160SwingVLow:
|
||||
case kHaierAc160SwingVLowest:
|
||||
_.Button = kHaierAcYrw02ButtonSwingV;
|
||||
_.SwingV = pos;
|
||||
break;
|
||||
default: return; // If in doubt, Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Timer operating mode.
|
||||
/// @param[in] mode The timer mode to use.
|
||||
void IRHaierAC160::setTimerMode(const uint8_t mode) {
|
||||
_.TimerMode = (mode > kHaierAcYrw02OffThenOnTimer) ? kHaierAcYrw02NoTimers
|
||||
: mode;
|
||||
switch (_.TimerMode) {
|
||||
case kHaierAcYrw02NoTimers:
|
||||
setOnTimer(0); // Disable the On timer.
|
||||
setOffTimer(0); // Disable the Off timer.
|
||||
break;
|
||||
case kHaierAcYrw02OffTimer:
|
||||
setOnTimer(0); // Disable the On timer.
|
||||
break;
|
||||
case kHaierAcYrw02OnTimer:
|
||||
setOffTimer(0); // Disable the Off timer.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Timer operating mode.
|
||||
/// @return The mode of the timer is currently configured to.
|
||||
uint8_t IRHaierAC160::getTimerMode(void) const { return _.TimerMode; }
|
||||
|
||||
/// Set the number of minutes of the On Timer setting.
|
||||
/// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
|
||||
void IRHaierAC160::setOnTimer(const uint16_t mins) {
|
||||
const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins);
|
||||
_.OnTimerHrs = nr_mins / 60;
|
||||
_.OnTimerMins = nr_mins % 60;
|
||||
|
||||
const bool enabled = (nr_mins > 0);
|
||||
uint8_t mode = getTimerMode();
|
||||
switch (mode) {
|
||||
case kHaierAcYrw02OffTimer:
|
||||
mode = enabled ? kHaierAcYrw02OffThenOnTimer : mode;
|
||||
break;
|
||||
case kHaierAcYrw02OnThenOffTimer:
|
||||
case kHaierAcYrw02OffThenOnTimer:
|
||||
mode = enabled ? kHaierAcYrw02OffThenOnTimer : kHaierAcYrw02OffTimer;
|
||||
break;
|
||||
default:
|
||||
// Enable/Disable the On timer for the simple case.
|
||||
mode = enabled << 1;
|
||||
}
|
||||
_.TimerMode = mode;
|
||||
}
|
||||
|
||||
/// Get the number of minutes of the On Timer setting.
|
||||
/// @return Nr of minutes.
|
||||
uint16_t IRHaierAC160::getOnTimer(void) const {
|
||||
return _.OnTimerHrs * 60 + _.OnTimerMins;
|
||||
}
|
||||
|
||||
/// Set the number of minutes of the Off Timer setting.
|
||||
/// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
|
||||
void IRHaierAC160::setOffTimer(const uint16_t mins) {
|
||||
const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins);
|
||||
_.OffTimerHrs = nr_mins / 60;
|
||||
_.OffTimerMins = nr_mins % 60;
|
||||
|
||||
const bool enabled = (nr_mins > 0);
|
||||
uint8_t mode = getTimerMode();
|
||||
switch (mode) {
|
||||
case kHaierAcYrw02OnTimer:
|
||||
mode = enabled ? kHaierAcYrw02OnThenOffTimer : mode;
|
||||
break;
|
||||
case kHaierAcYrw02OnThenOffTimer:
|
||||
case kHaierAcYrw02OffThenOnTimer:
|
||||
mode = enabled ? kHaierAcYrw02OnThenOffTimer : kHaierAcYrw02OnTimer;
|
||||
break;
|
||||
default:
|
||||
// Enable/Disable the Off timer for the simple case.
|
||||
mode = enabled;
|
||||
}
|
||||
_.TimerMode = mode;
|
||||
}
|
||||
|
||||
/// Get the number of minutes of the Off Timer setting.
|
||||
/// @return Nr of minutes.
|
||||
uint16_t IRHaierAC160::getOffTimer(void) const {
|
||||
return _.OffTimerHrs * 60 + _.OffTimerMins;
|
||||
}
|
||||
|
||||
/// Get the Lock setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC160::getLock(void) const { return _.Lock; }
|
||||
|
||||
/// Set the Lock setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC160::setLock(const bool on) {
|
||||
_.Button = kHaierAcYrw02ButtonLock;
|
||||
_.Lock = on;
|
||||
}
|
||||
|
||||
/// Convert a stdAc::opmode_t enum into its native mode.
|
||||
/// @param[in] mode The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRHaierAC160::convertMode(const stdAc::opmode_t mode) {
|
||||
switch (mode) {
|
||||
case stdAc::opmode_t::kCool: return kHaierAcYrw02Cool;
|
||||
case stdAc::opmode_t::kHeat: return kHaierAcYrw02Heat;
|
||||
case stdAc::opmode_t::kDry: return kHaierAcYrw02Dry;
|
||||
case stdAc::opmode_t::kFan: return kHaierAcYrw02Fan;
|
||||
default: return kHaierAcYrw02Auto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::fanspeed_t enum into it's native speed.
|
||||
/// @param[in] speed The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRHaierAC160::convertFan(const stdAc::fanspeed_t speed) {
|
||||
switch (speed) {
|
||||
case stdAc::fanspeed_t::kMin:
|
||||
case stdAc::fanspeed_t::kLow: return kHaierAcYrw02FanLow;
|
||||
case stdAc::fanspeed_t::kMedium: return kHaierAcYrw02FanMed;
|
||||
case stdAc::fanspeed_t::kHigh:
|
||||
case stdAc::fanspeed_t::kMax: return kHaierAcYrw02FanHigh;
|
||||
default: return kHaierAcYrw02FanAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingv_t enum into it's native setting.
|
||||
/// @param[in] position The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRHaierAC160::convertSwingV(const stdAc::swingv_t position) {
|
||||
switch (position) {
|
||||
case stdAc::swingv_t::kHighest: return kHaierAc160SwingVTop;
|
||||
case stdAc::swingv_t::kHigh: return kHaierAc160SwingVHigh;
|
||||
case stdAc::swingv_t::kMiddle: return kHaierAc160SwingVMiddle;
|
||||
case stdAc::swingv_t::kLow: return kHaierAc160SwingVLow;
|
||||
case stdAc::swingv_t::kLowest: return kHaierAc160SwingVLowest;
|
||||
case stdAc::swingv_t::kOff: return kHaierAc160SwingVOff;
|
||||
default: return kHaierAc160SwingVAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native mode into its stdAc equivalent.
|
||||
/// @param[in] mode The native setting to be converted.
|
||||
/// @return The stdAc equivalent of the native setting.
|
||||
stdAc::opmode_t IRHaierAC160::toCommonMode(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kHaierAcYrw02Cool: return stdAc::opmode_t::kCool;
|
||||
case kHaierAcYrw02Heat: return stdAc::opmode_t::kHeat;
|
||||
case kHaierAcYrw02Dry: return stdAc::opmode_t::kDry;
|
||||
case kHaierAcYrw02Fan: return stdAc::opmode_t::kFan;
|
||||
default: return stdAc::opmode_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native fan speed into its stdAc equivalent.
|
||||
/// @param[in] speed The native setting to be converted.
|
||||
/// @return The stdAc equivalent of the native setting.
|
||||
stdAc::fanspeed_t IRHaierAC160::toCommonFanSpeed(const uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kHaierAcYrw02FanHigh: return stdAc::fanspeed_t::kMax;
|
||||
case kHaierAcYrw02FanMed: return stdAc::fanspeed_t::kMedium;
|
||||
case kHaierAcYrw02FanLow: return stdAc::fanspeed_t::kMin;
|
||||
default: return stdAc::fanspeed_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingv_t enum into it's native setting.
|
||||
/// @param[in] pos The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
stdAc::swingv_t IRHaierAC160::toCommonSwingV(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kHaierAc160SwingVTop:
|
||||
case kHaierAc160SwingVHighest: return stdAc::swingv_t::kHighest;
|
||||
case kHaierAc160SwingVHigh: return stdAc::swingv_t::kHigh;
|
||||
case kHaierAc160SwingVMiddle: return stdAc::swingv_t::kMiddle;
|
||||
case kHaierAc160SwingVLow: return stdAc::swingv_t::kLow;
|
||||
case kHaierAc160SwingVLowest: return stdAc::swingv_t::kLowest;
|
||||
case kHaierAc160SwingVOff: return stdAc::swingv_t::kOff;
|
||||
default: return stdAc::swingv_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(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);
|
||||
result.celsius = !_.UseFahrenheit;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(_.Fan);
|
||||
result.swingv = toCommonSwingV(_.SwingV);
|
||||
result.swingh = stdAc::swingh_t::kOff;
|
||||
result.sleep = _.Sleep ? 0 : -1;
|
||||
result.turbo = _.Turbo;
|
||||
result.quiet = _.Quiet;
|
||||
result.clean = _.Clean && _.Clean2;
|
||||
result.light ^= getLightToggle();
|
||||
result.filter = _.Health;
|
||||
// Not supported.
|
||||
result.model = -1;
|
||||
result.econo = false;
|
||||
result.beep = true;
|
||||
result.clock = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Convert the current internal state into a human readable string.
|
||||
/// @return A human readable string.
|
||||
String IRHaierAC160::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(280); // Reserve some heap for the string to reduce fragging.
|
||||
result += addBoolToString(_.Power, kPowerStr, false);
|
||||
uint8_t cmd = _.Button;
|
||||
result += addIntToString(cmd, kButtonStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (cmd) {
|
||||
case kHaierAcYrw02ButtonPower:
|
||||
result += kPowerStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonMode:
|
||||
result += kModeStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonFan:
|
||||
result += kFanStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonTempUp:
|
||||
result += kTempUpStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonTempDown:
|
||||
result += kTempDownStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonSleep:
|
||||
result += kSleepStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonHealth:
|
||||
result += kHealthStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonSwingV:
|
||||
result += kSwingVStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonSwingH:
|
||||
result += kSwingHStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonTurbo:
|
||||
result += kTurboStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonTimer:
|
||||
result += kTimerStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonLock:
|
||||
result += kLockStr;
|
||||
break;
|
||||
case kHaierAc160ButtonClean:
|
||||
result += kCleanStr;
|
||||
break;
|
||||
case kHaierAc160ButtonLight:
|
||||
result += kLightStr;
|
||||
break;
|
||||
case kHaierAc160ButtonAuxHeating:
|
||||
result += kHeatingStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonCFAB:
|
||||
result += kCelsiusFahrenheitStr;
|
||||
break;
|
||||
default:
|
||||
result += kUnknownStr;
|
||||
}
|
||||
result += ')';
|
||||
result += addModeToString(_.Mode, kHaierAcYrw02Auto, kHaierAcYrw02Cool,
|
||||
kHaierAcYrw02Heat, kHaierAcYrw02Dry,
|
||||
kHaierAcYrw02Fan);
|
||||
result += addTempToString(getTemp(), !_.UseFahrenheit);
|
||||
result += addFanToString(_.Fan, kHaierAcYrw02FanHigh, kHaierAcYrw02FanLow,
|
||||
kHaierAcYrw02FanAuto, kHaierAcYrw02FanAuto,
|
||||
kHaierAcYrw02FanMed);
|
||||
result += addBoolToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.Quiet, kQuietStr);
|
||||
result += addBoolToString(_.Health, kHealthStr);
|
||||
result += addIntToString(_.SwingV, kSwingVStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (_.SwingV) {
|
||||
case kHaierAc160SwingVOff: result += kOffStr; break;
|
||||
case kHaierAc160SwingVAuto: result += kAutoStr; break;
|
||||
case kHaierAc160SwingVTop: result += kTopStr; break;
|
||||
case kHaierAc160SwingVHighest: result += kHighestStr; break;
|
||||
case kHaierAc160SwingVHigh: result += kHighStr; break;
|
||||
case kHaierAc160SwingVMiddle: result += kMiddleStr; break;
|
||||
case kHaierAc160SwingVLow: result += kLowStr; break;
|
||||
case kHaierAc160SwingVLowest: result += kLowestStr; break;
|
||||
default: result += kUnknownStr;
|
||||
}
|
||||
result += ')';
|
||||
result += addBoolToString(_.Sleep, kSleepStr);
|
||||
result += addBoolToString(getClean(), kCleanStr);
|
||||
const uint8_t tmode = getTimerMode();
|
||||
result += addIntToString(tmode, kTimerModeStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (tmode) {
|
||||
case kHaierAcYrw02NoTimers:
|
||||
result += kNAStr;
|
||||
break;
|
||||
case kHaierAcYrw02OnTimer:
|
||||
result += kOnStr;
|
||||
break;
|
||||
case kHaierAcYrw02OffTimer:
|
||||
result += kOffStr;
|
||||
break;
|
||||
case kHaierAcYrw02OnThenOffTimer:
|
||||
result += kOnStr;
|
||||
result += '-';
|
||||
result += kOffStr;
|
||||
break;
|
||||
case kHaierAcYrw02OffThenOnTimer:
|
||||
result += kOffStr;
|
||||
result += '-';
|
||||
result += kOnStr;
|
||||
break;
|
||||
default:
|
||||
result += kUnknownStr;
|
||||
}
|
||||
result += ')';
|
||||
result += addLabeledString((tmode != kHaierAcYrw02NoTimers &&
|
||||
tmode != kHaierAcYrw02OffTimer) ?
|
||||
minsToString(getOnTimer()) : kOffStr, kOnTimerStr);
|
||||
result += addLabeledString((tmode != kHaierAcYrw02NoTimers &&
|
||||
tmode != kHaierAcYrw02OnTimer) ?
|
||||
minsToString(getOffTimer()) : kOffStr, kOffTimerStr);
|
||||
result += addBoolToString(_.Lock, kLockStr);
|
||||
result += addBoolToString(_.AuxHeating, kHeatingStr);
|
||||
return result;
|
||||
}
|
||||
// End of IRHaierAC160 class.
|
||||
|
||||
174
src/ir_Haier.h
174
src/ir_Haier.h
@@ -146,6 +146,7 @@ const uint8_t kHaierAcYrw02DefTempC = 25;
|
||||
const uint8_t kHaierAcYrw02ModelA = 0xA6;
|
||||
const uint8_t kHaierAcYrw02ModelB = 0x59;
|
||||
const uint8_t kHaierAc176Prefix = 0xB7;
|
||||
const uint8_t kHaierAc160Prefix = 0xB5;
|
||||
|
||||
const uint8_t kHaierAcYrw02SwingVOff = 0x0;
|
||||
const uint8_t kHaierAcYrw02SwingVTop = 0x1;
|
||||
@@ -154,6 +155,15 @@ const uint8_t kHaierAcYrw02SwingVBottom = 0x3; // Only available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingVDown = 0xA;
|
||||
const uint8_t kHaierAcYrw02SwingVAuto = 0xC; // Airflow
|
||||
|
||||
const uint8_t kHaierAc160SwingVOff = 0b0000;
|
||||
const uint8_t kHaierAc160SwingVTop = 0b0001;
|
||||
const uint8_t kHaierAc160SwingVHighest = 0b0010;
|
||||
const uint8_t kHaierAc160SwingVHigh = 0b0100;
|
||||
const uint8_t kHaierAc160SwingVMiddle = 0b0110;
|
||||
const uint8_t kHaierAc160SwingVLow = 0b1000;
|
||||
const uint8_t kHaierAc160SwingVLowest = 0b0011;
|
||||
const uint8_t kHaierAc160SwingVAuto = 0b1100; // Airflow
|
||||
|
||||
const uint8_t kHaierAcYrw02SwingHMiddle = 0x0;
|
||||
const uint8_t kHaierAcYrw02SwingHLeftMax = 0x3;
|
||||
const uint8_t kHaierAcYrw02SwingHLeft = 0x4;
|
||||
@@ -184,6 +194,9 @@ 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 kHaierAc160ButtonAuxHeating = 0b10110;
|
||||
const uint8_t kHaierAc160ButtonClean = 0b11001;
|
||||
const uint8_t kHaierAcYrw02ButtonCFAB = 0b11010;
|
||||
|
||||
const uint8_t kHaierAcYrw02NoTimers = 0b000;
|
||||
@@ -262,6 +275,75 @@ union HaierAc176Protocol{
|
||||
};
|
||||
};
|
||||
|
||||
/// Native representation of a Haier 160 bit A/C message.
|
||||
union HaierAc160Protocol{
|
||||
uint8_t raw[kHaierAC160StateLength]; ///< The state in native form
|
||||
struct {
|
||||
// Byte 0
|
||||
uint8_t Model :8;
|
||||
// Byte 1
|
||||
uint8_t SwingV :4;
|
||||
uint8_t Temp :4; // 16C~30C
|
||||
// Byte 2
|
||||
uint8_t :5;
|
||||
uint8_t SwingH :3;
|
||||
// Byte 3
|
||||
uint8_t :1;
|
||||
uint8_t Health :1;
|
||||
uint8_t :3;
|
||||
uint8_t TimerMode :3;
|
||||
// Byte 4
|
||||
uint8_t :6;
|
||||
uint8_t Power :1;
|
||||
uint8_t AuxHeating :1;
|
||||
// Byte 5
|
||||
uint8_t OffTimerHrs :5;
|
||||
uint8_t Fan :3;
|
||||
// Byte 6
|
||||
uint8_t OffTimerMins:6;
|
||||
uint8_t Turbo :1;
|
||||
uint8_t Quiet :1;
|
||||
// Byte 7
|
||||
uint8_t OnTimerHrs :5;
|
||||
uint8_t Mode :3;
|
||||
// Byte 8
|
||||
uint8_t OnTimerMins :6;
|
||||
uint8_t :1;
|
||||
uint8_t Sleep :1;
|
||||
// Byte 9
|
||||
uint8_t :8;
|
||||
// Byte 10
|
||||
uint8_t ExtraDegreeF :1;
|
||||
uint8_t :3;
|
||||
uint8_t Clean :1;
|
||||
uint8_t UseFahrenheit:1;
|
||||
uint8_t :2;
|
||||
// Byte 11
|
||||
uint8_t :8;
|
||||
// Byte 12
|
||||
uint8_t Button :5;
|
||||
uint8_t Lock :1;
|
||||
uint8_t :2;
|
||||
// Byte 13
|
||||
uint8_t Sum :8;
|
||||
// Byte 14
|
||||
uint8_t Prefix :8;
|
||||
// Byte 15
|
||||
uint8_t :6;
|
||||
uint8_t Clean2 :1;
|
||||
uint8_t :1;
|
||||
// Byte 16
|
||||
uint8_t :5;
|
||||
uint8_t Fan2 :3;
|
||||
// Byte 17
|
||||
uint8_t :8;
|
||||
// Byte 18
|
||||
uint8_t :8;
|
||||
// Byte 19
|
||||
uint8_t Sum2 :8;
|
||||
};
|
||||
};
|
||||
|
||||
// Legacy Haier YRW02 remote defines.
|
||||
#define HAIER_AC_YRW02_SWING_OFF kHaierAcYrw02SwingOff
|
||||
#define HAIER_AC_YRW02_SWING_TOP kHaierAcYrw02SwingTop
|
||||
@@ -476,4 +558,96 @@ class IRHaierACYRW02 : public IRHaierAC176 {
|
||||
const uint8_t state[],
|
||||
const uint16_t length = kHaierACYRW02StateLength);
|
||||
};
|
||||
|
||||
/// Class for handling detailed Haier 160 bit A/C messages.
|
||||
class IRHaierAC160 {
|
||||
public:
|
||||
explicit IRHaierAC160(const uint16_t pin, const bool inverted = false,
|
||||
const bool use_modulation = true);
|
||||
#if SEND_HAIER_AC160
|
||||
virtual void send(const uint16_t repeat = kHaierAc160DefaultRepeat);
|
||||
/// Run the calibration to calculate uSec timing offsets for this platform.
|
||||
/// @return The uSec timing offset needed per modulation of the IR Led.
|
||||
/// @note This will produce a 65ms IR signal pulse at 38kHz.
|
||||
/// Only ever needs to be run once per object instantiation, if at all.
|
||||
int8_t calibrate(void) { return _irsend.calibrate(); }
|
||||
#endif // SEND_HAIER_AC160
|
||||
void begin(void);
|
||||
void stateReset(void);
|
||||
|
||||
void setButton(const uint8_t button);
|
||||
uint8_t getButton(void) const;
|
||||
|
||||
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);
|
||||
uint8_t getFan(void) const;
|
||||
|
||||
uint8_t getMode(void) const;
|
||||
void setMode(const uint8_t mode);
|
||||
|
||||
bool getPower(void) const;
|
||||
void setPower(const bool on);
|
||||
void on(void);
|
||||
void off(void);
|
||||
|
||||
bool getSleep(void) const;
|
||||
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);
|
||||
bool getQuiet(void) const;
|
||||
void setQuiet(const bool on);
|
||||
bool getAuxHeating(void) const;
|
||||
void setAuxHeating(const bool on);
|
||||
|
||||
uint8_t getSwingV(void) const;
|
||||
void setSwingV(const uint8_t pos);
|
||||
|
||||
void setTimerMode(const uint8_t setting);
|
||||
uint8_t getTimerMode(void) const;
|
||||
void setOnTimer(const uint16_t mins);
|
||||
uint16_t getOnTimer(void) const;
|
||||
void setOffTimer(const uint16_t mins);
|
||||
uint16_t getOffTimer(void) const;
|
||||
|
||||
bool getLock(void) const;
|
||||
void setLock(const bool on);
|
||||
|
||||
bool getHealth(void) const;
|
||||
void setHealth(const bool on);
|
||||
|
||||
uint8_t* getRaw(void);
|
||||
virtual void setRaw(const uint8_t new_code[]);
|
||||
static bool validChecksum(const uint8_t state[],
|
||||
const uint16_t length = kHaierAC160StateLength);
|
||||
static uint8_t convertMode(const stdAc::opmode_t mode);
|
||||
static uint8_t convertFan(const stdAc::fanspeed_t speed);
|
||||
static uint8_t convertSwingV(const stdAc::swingv_t position);
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
|
||||
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(const stdAc::state_t *prev = NULL) const;
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
||||
private:
|
||||
IRsend _irsend; ///< Instance of the IR send class
|
||||
#else // UNIT_TEST
|
||||
/// @cond IGNORE
|
||||
IRsendTest _irsend; ///< Instance of the testing IR send class
|
||||
/// @endcond
|
||||
#endif // UNIT_TEST
|
||||
HaierAc160Protocol _;
|
||||
void checksum(void);
|
||||
};
|
||||
#endif // IR_HAIER_H_
|
||||
|
||||
@@ -820,6 +820,41 @@ TEST(TestIRac, Haier) {
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
|
||||
}
|
||||
|
||||
TEST(TestIRac, Haier160) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
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, Health: On, "
|
||||
"Swing(V): 4 (High), Sleep: On, "
|
||||
"Clean: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, "
|
||||
"Lock: Off, Heating: Off";
|
||||
ac.begin();
|
||||
irac.haier160(&ac,
|
||||
true, // Power
|
||||
stdAc::opmode_t::kCool, // Mode
|
||||
true, // Celsius
|
||||
23, // Degrees
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kHigh, // Vertical swing
|
||||
true, // Turbo
|
||||
false, // Quiet
|
||||
true, // Filter/Health
|
||||
true, // Clean
|
||||
true, // Light
|
||||
true, // Light (prev)
|
||||
8 * 60 + 0); // Sleep time
|
||||
ASSERT_EQ(expected, ac.toString());
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(HAIER_AC160, ac._irsend.capture.decode_type);
|
||||
ASSERT_EQ(kHaierAC160Bits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
|
||||
}
|
||||
|
||||
TEST(TestIRac, Haier176) {
|
||||
IRHaierAC176 ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
|
||||
@@ -1361,7 +1361,7 @@ TEST(TestUtils, Housekeeping) {
|
||||
ASSERT_EQ("HAIER_AC160", typeToString(decode_type_t::HAIER_AC160));
|
||||
ASSERT_EQ(decode_type_t::HAIER_AC160, strToDecodeType("HAIER_AC160"));
|
||||
ASSERT_TRUE(hasACState(decode_type_t::HAIER_AC160));
|
||||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HAIER_AC160));
|
||||
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HAIER_AC160));
|
||||
ASSERT_EQ(kHaierAC160Bits, IRsend::defaultBits(decode_type_t::HAIER_AC160));
|
||||
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::HAIER_AC160));
|
||||
}
|
||||
@@ -1588,10 +1588,14 @@ TEST(TestDecodeHaierAC160, RealExample) {
|
||||
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: 26C, Fan: 3 (Low), "
|
||||
"Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), Sleep: Off, "
|
||||
"Clean: Off, "
|
||||
"Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off, "
|
||||
"Heating: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t result, prev;
|
||||
ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
|
||||
}
|
||||
|
||||
// Decoding a message we entirely constructed based solely on a given state.
|
||||
@@ -1613,8 +1617,417 @@ TEST(TestDecodeHaierAC160, SyntheticExample) {
|
||||
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: 26C, Fan: 3 (Low), "
|
||||
"Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), Sleep: Off, "
|
||||
"Clean: Off, "
|
||||
"Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off, "
|
||||
"Heating: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t result, prev;
|
||||
ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
|
||||
}
|
||||
|
||||
// Tests for the IRHaierAC160 class.
|
||||
|
||||
TEST(TestHaierAC160Class, Button) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonPower);
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton());
|
||||
ac.setButton(kHaierAcYrw02ButtonMode);
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonMode, ac.getButton());
|
||||
ac.setButton(kHaierAcYrw02ButtonSleep);
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton());
|
||||
ac.setButton(kHaierAcYrw02ButtonFan);
|
||||
|
||||
// Test unexpected values.
|
||||
ac.setButton(0xFF);
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton());
|
||||
ac.setButton(0x10);
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, OperatingMode) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonPower);
|
||||
ac.setMode(kHaierAcYrw02Auto);
|
||||
EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonMode, ac.getButton());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Cool);
|
||||
EXPECT_EQ(kHaierAcYrw02Cool, ac.getMode());
|
||||
EXPECT_FALSE(ac.getAuxHeating());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Heat);
|
||||
EXPECT_EQ(kHaierAcYrw02Heat, ac.getMode());
|
||||
EXPECT_TRUE(ac.getAuxHeating());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Fan);
|
||||
EXPECT_EQ(kHaierAcYrw02Fan, ac.getMode());
|
||||
EXPECT_FALSE(ac.getAuxHeating());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Dry);
|
||||
EXPECT_EQ(kHaierAcYrw02Dry, ac.getMode());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Auto - 1);
|
||||
EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Cool);
|
||||
EXPECT_EQ(kHaierAcYrw02Cool, ac.getMode());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Fan + 1);
|
||||
EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode());
|
||||
|
||||
ac.setMode(255);
|
||||
EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, Temperature) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setTemp(kHaierAcYrw02MinTempC);
|
||||
EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonPower);
|
||||
ac.setTemp(kHaierAcYrw02MinTempC + 1);
|
||||
EXPECT_EQ(kHaierAcYrw02MinTempC + 1, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton());
|
||||
|
||||
ac.setTemp(kHaierAcYrw02MaxTempC);
|
||||
EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton());
|
||||
|
||||
ac.setTemp(kHaierAcYrw02MinTempC - 1);
|
||||
EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton());
|
||||
|
||||
ac.setTemp(kHaierAcYrw02MaxTempC + 1);
|
||||
EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton());
|
||||
|
||||
ac.setTemp(23);
|
||||
EXPECT_EQ(23, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton());
|
||||
ac.setButton(kHaierAcYrw02ButtonPower);
|
||||
ac.setTemp(23);
|
||||
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(kHaierAcYrw02ButtonCFAB, ac.getButton());
|
||||
|
||||
ac.setTemp(0);
|
||||
EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton());
|
||||
|
||||
ac.setTemp(255);
|
||||
EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, CleanMode) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setClean(true);
|
||||
EXPECT_TRUE(ac.getClean());
|
||||
EXPECT_EQ(kHaierAc160ButtonClean, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setClean(false);
|
||||
EXPECT_FALSE(ac.getClean());
|
||||
EXPECT_EQ(kHaierAc160ButtonClean, ac.getButton());
|
||||
|
||||
ac.setClean(true);
|
||||
EXPECT_TRUE(ac.getClean());
|
||||
EXPECT_EQ(kHaierAc160ButtonClean, ac.getButton());
|
||||
|
||||
ac.stateReset();
|
||||
EXPECT_FALSE(ac.getClean());
|
||||
// clean button pressed.
|
||||
// https://docs.google.com/spreadsheets/d/1RNJ7esbArS5fy1lmiM-i1PekXSNojCMad4WuuyunsC8/edit#gid=2048081808&range=FR22
|
||||
const uint8_t clean_on[kHaierAC160StateLength] = {
|
||||
0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00,
|
||||
0x10, 0x00, 0x19, 0x3B, 0xB5, 0x40, 0x60, 0x00, 0x00, 0x55};
|
||||
ac.setRaw(clean_on);
|
||||
EXPECT_TRUE(ac.getClean());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Button: 25 (Clean), Mode: 1 (Cool), Temp: 26C, "
|
||||
"Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), "
|
||||
"Sleep: Off, Clean: On, Timer Mode: 0 (N/A), "
|
||||
"On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off",
|
||||
ac.toString());
|
||||
// No clean set.
|
||||
// https://docs.google.com/spreadsheets/d/1RNJ7esbArS5fy1lmiM-i1PekXSNojCMad4WuuyunsC8/edit#gid=2048081808&range=FR4
|
||||
const uint8_t clean_off[kHaierAC160StateLength] = {
|
||||
0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00,
|
||||
0x00, 0x00, 0x05, 0x17, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15};
|
||||
ac.setRaw(clean_off);
|
||||
EXPECT_FALSE(ac.getClean());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 26C, "
|
||||
"Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), "
|
||||
"Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), "
|
||||
"On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, Power) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setPower(true);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setPower(false);
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton());
|
||||
|
||||
ac.setPower(true);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton());
|
||||
|
||||
ac.off();
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
ac.on();
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, SleepMode) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setSleep(false);
|
||||
EXPECT_FALSE(ac.getSleep());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton());
|
||||
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, Health) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setHealth(true);
|
||||
EXPECT_TRUE(ac.getHealth());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setHealth(false);
|
||||
EXPECT_FALSE(ac.getHealth());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton());
|
||||
|
||||
ac.setHealth(true);
|
||||
EXPECT_TRUE(ac.getHealth());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, TurboAndQuiet) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setMode(kHaierAcYrw02Cool); // Turbo & Quiet is allowed in this mode.
|
||||
ac.setTurbo(false);
|
||||
ac.setQuiet(false);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
|
||||
ac.setTurbo(true);
|
||||
EXPECT_TRUE(ac.getTurbo());
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton());
|
||||
|
||||
ac.setQuiet(true);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_TRUE(ac.getQuiet());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton());
|
||||
|
||||
ac.setTurbo(false);
|
||||
ac.setQuiet(false);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton());
|
||||
|
||||
ac.setMode(kHaierAcYrw02Auto); // Turbo & Quiet is not allowed in this mode.
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
ac.setTurbo(true);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_NE(kHaierAcYrw02ButtonTurbo, ac.getButton());
|
||||
ac.setQuiet(true);
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
EXPECT_NE(kHaierAcYrw02ButtonTurbo, ac.getButton());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, Fan) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setFan(kHaierAcYrw02FanAuto);
|
||||
EXPECT_EQ(kHaierAcYrw02FanAuto, ac.getFan());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
|
||||
ac.setFan(kHaierAcYrw02FanLow);
|
||||
EXPECT_EQ(kHaierAcYrw02FanLow, ac.getFan());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton());
|
||||
|
||||
ac.setFan(kHaierAcYrw02FanHigh);
|
||||
EXPECT_EQ(kHaierAcYrw02FanHigh, ac.getFan());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton());
|
||||
|
||||
ac.setFan(kHaierAcYrw02FanMed);
|
||||
EXPECT_EQ(kHaierAcYrw02FanMed, ac.getFan());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton());
|
||||
|
||||
// Test unexpected values.
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setFan(0x00);
|
||||
EXPECT_EQ(kHaierAcYrw02FanMed, ac.getFan());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, SwingV) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setSwingV(kHaierAc160SwingVOff);
|
||||
EXPECT_EQ(kHaierAc160SwingVOff, ac.getSwingV());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
|
||||
ac.setSwingV(kHaierAc160SwingVAuto);
|
||||
EXPECT_EQ(kHaierAc160SwingVAuto, ac.getSwingV());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton());
|
||||
|
||||
ac.setSwingV(kHaierAc160SwingVTop);
|
||||
EXPECT_EQ(kHaierAc160SwingVTop, ac.getSwingV());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton());
|
||||
|
||||
ac.setSwingV(kHaierAc160SwingVLow);
|
||||
EXPECT_EQ(kHaierAc160SwingVLow, ac.getSwingV());
|
||||
EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton());
|
||||
|
||||
// Test unexpected values.
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setSwingV(0xFF);
|
||||
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, Health: Off, Swing(V): 12 (Auto), "
|
||||
"Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), "
|
||||
"On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestHaierAC160Class, AuxHeating) {
|
||||
IRHaierAC160 ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setAuxHeating(true);
|
||||
EXPECT_TRUE(ac.getAuxHeating());
|
||||
EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton());
|
||||
|
||||
ac.setButton(kHaierAcYrw02ButtonTempUp);
|
||||
ac.setAuxHeating(false);
|
||||
EXPECT_FALSE(ac.getAuxHeating());
|
||||
EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton());
|
||||
|
||||
ac.setAuxHeating(true);
|
||||
EXPECT_TRUE(ac.getAuxHeating());
|
||||
EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton());
|
||||
|
||||
// https://docs.google.com/spreadsheets/d/1RNJ7esbArS5fy1lmiM-i1PekXSNojCMad4WuuyunsC8/edit#gid=2048081808&range=A124:W143
|
||||
const uint8_t aux_button_off[kHaierAC160StateLength] = {
|
||||
0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x16, 0x88, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15};
|
||||
ac.setRaw(aux_button_off);
|
||||
EXPECT_FALSE(ac.getAuxHeating());
|
||||
EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Button: 22 (Heating), Mode: 4 (Heat), Temp: 26C, "
|
||||
"Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), "
|
||||
"Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), "
|
||||
"On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user