Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HAIER_AC176/HAIER_AC_YRW02] Add support A/B unit setting #1672

Merged
merged 4 commits into from
Nov 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -3313,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;
Expand Down
10 changes: 5 additions & 5 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions src/IRtext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -606,6 +607,16 @@ namespace irutils {
default: return kUnknownStr;
}
break;
case decode_type_t::HAIER_AC176:
crankyoldgit marked this conversation as resolved.
Show resolved Hide resolved
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:
Expand Down
43 changes: 34 additions & 9 deletions src/ir_Haier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -619,11 +620,33 @@ void IRHaierAC176::setButton(uint8_t button) {
case kHaierAcYrw02ButtonTurbo:
case kHaierAcYrw02ButtonSleep:
case kHaierAcYrw02ButtonLock:
case kHaierAcYrw02ButtonCF:
case kHaierAcYrw02ButtonCFAB:
_.Button = 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) {
_.Button = kHaierAcYrw02ButtonCFAB;
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 {
Expand Down Expand Up @@ -677,7 +700,7 @@ void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) {
else
_.Button = kHaierAcYrw02ButtonTempUp;
} else {
_.Button = kHaierAcYrw02ButtonCF;
_.Button = kHaierAcYrw02ButtonCFAB;
}
_.UseFahrenheit = fahrenheit;

Expand Down Expand Up @@ -1106,7 +1129,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;
Expand All @@ -1131,8 +1154,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);
uint8_t cmd = _.Button;
result += addIntToString(cmd, kButtonStr);
result += kSpaceLBraceStr;
Expand Down Expand Up @@ -1173,7 +1197,7 @@ String IRHaierAC176::toString(void) const {
case kHaierAcYrw02ButtonLock:
result += kLockStr;
break;
case kHaierAcYrw02ButtonCF:
case kHaierAcYrw02ButtonCFAB:
result += kCelsiusFahrenheitStr;
break;
default:
Expand Down Expand Up @@ -1367,7 +1391,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;
}

Expand Down Expand Up @@ -1400,7 +1424,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;
}

Expand Down
10 changes: 7 additions & 3 deletions src/ir_Haier.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -179,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;
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 18 additions & 17 deletions test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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();
Expand Down
Loading