Skip to content

Commit

Permalink
Hitachi344: Add Swing(H) and improve Swing(V) (#1148)
Browse files Browse the repository at this point in the history
* Hitachi344: Add Swing(H) and improve Swing(V)
* Correct Swing(V) control
* Add Swing(H) support.
* Update common A/C support.
* Reduce duplicate code between 344 & 424 classes.
* add & update supporting Unit Tests.
* Update supported models
* Improve doxygen comments.
* Fix typo

Fixes #1134
  • Loading branch information
crankyoldgit authored May 31, 2020
1 parent c1b1c50 commit c56b9cd
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 39 deletions.
13 changes: 8 additions & 5 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,15 +812,14 @@ void IRac::hitachi1(IRHitachiAc1 *ac, const hitachi_ac1_remote_model_t model,
void IRac::hitachi344(IRHitachiAc344 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv) {
const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh) {
ac->begin();
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
ac->setFan(ac->convertFan(fan));
ac->setSwingH(ac->convertSwingH(swingh));
ac->setPower(on);
// SwingVToggle is special. Needs to be last method called.
ac->setSwingVToggle(swingv != stdAc::swingv_t::kOff);
// No Swing(H) setting available.
// No Quiet setting available.
// No Turbo setting available.
// No Light setting available.
Expand All @@ -829,6 +828,9 @@ void IRac::hitachi344(IRHitachiAc344 *ac,
// No Beep setting available.
// No Sleep setting available.
// No Clock setting available.

// SwingVToggle is special. Needs to be last method called.
ac->setSwingVToggle(swingv != stdAc::swingv_t::kOff);
ac->send();
}
#endif // SEND_HITACHI_AC344
Expand Down Expand Up @@ -1691,7 +1693,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case HITACHI_AC344:
{
IRHitachiAc344 ac(_pin, _inverted, _modulation);
hitachi344(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv);
hitachi344(&ac, send.power, send.mode, degC, send.fanspeed,
send.swingv, send.swingh);
break;
}
#endif // SEND_HITACHI_AC344
Expand Down
3 changes: 2 additions & 1 deletion src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ void electra(IRElectraAc *ac,
void hitachi344(IRHitachiAc344 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv);
const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh);
#endif // SEND_HITACHI_AC344
#if SEND_HITACHI_AC424
void hitachi424(IRHitachiAc424 *ac,
Expand Down
97 changes: 94 additions & 3 deletions src/ir_Hitachi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1156,8 +1156,10 @@ stdAc::state_t IRHitachiAc424::toCommon(void) {
return result;
}

// Convert the internal state into a human readable string.
String IRHitachiAc424::toString(void) {
/// Convert the internal state into a human readable string for the settings
/// that are common to protocols of this nature.
/// @return A string containing the common settings in human-readable form.
String IRHitachiAc424::_toString(void) {
String result = "";
result.reserve(100); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), kPowerStr, false);
Expand All @@ -1177,7 +1179,6 @@ String IRHitachiAc424::toString(void) {
default: result += kUnknownStr;
}
result += ')';
result += addBoolToString(getSwingVToggle(), kSwingVToggleStr);
result += addIntToString(getButton(), kButtonStr);
result += kSpaceLBraceStr;
switch (getButton()) {
Expand All @@ -1188,6 +1189,7 @@ String IRHitachiAc424::toString(void) {
break;
case kHitachiAc424ButtonFan: result += kFanStr; break;
case kHitachiAc424ButtonSwingV: result += kSwingVStr; break;
case kHitachiAc344ButtonSwingH: result += kSwingHStr; break;
case kHitachiAc424ButtonTempDown: result += kTempDownStr; break;
case kHitachiAc424ButtonTempUp: result += kTempUpStr; break;
default: result += kUnknownStr;
Expand All @@ -1196,6 +1198,12 @@ String IRHitachiAc424::toString(void) {
return result;
}

/// Convert the internal state into a human readable string.
/// @return A string containing the settings in human-readable form.
String IRHitachiAc424::toString(void) {
return _toString() + addBoolToString(getSwingVToggle(), kSwingVToggleStr);
}


#if SEND_HITACHI_AC3
// Send HITACHI_AC3 messages
Expand Down Expand Up @@ -1366,10 +1374,93 @@ void IRHitachiAc344::setRaw(const uint8_t new_code[], const uint16_t length) {
memcpy(remote_state, new_code, std::min(length, kHitachiAc344StateLength));
}

/// Control the vertical swing setting.
/// @param[in] on True, turns on the feature. False, turns off the feature.
void IRHitachiAc344::setSwingV(const bool on) {
setSwingVToggle(on); // Set the button value.
setBit(&remote_state[kHitachiAc344SwingVByte], kHitachiAc344SwingVOffset, on);
}

/// Get the current vertical swing setting.
/// @return True, if the setting is on. False, it is off.
bool IRHitachiAc344::getSwingV(void) {
return GETBIT8(remote_state[kHitachiAc344SwingVByte],
kHitachiAc344SwingVOffset);
}

/// Control the horizontal swing setting.
/// @param[in] position The position to set the horizontal swing to.
void IRHitachiAc344::setSwingH(const uint8_t position) {
if (position > kHitachiAc344SwingHLeftMax)
return setSwingH(kHitachiAc344SwingHMiddle);
setBits(&remote_state[kHitachiAc344SwingHByte], kHitachiAc344SwingHOffset,
kHitachiAc344SwingHSize, position);
setButton(kHitachiAc344ButtonSwingH);
}

/// Get the current horizontal swing setting.
/// @return The current position horizontal swing is set to.
uint8_t IRHitachiAc344::getSwingH(void) {
return GETBITS8(remote_state[kHitachiAc344SwingHByte],
kHitachiAc344SwingHOffset, kHitachiAc344SwingHSize);
}

/// Convert a standard A/C horizontal swing into its native setting.
/// @param[in] position A stdAc::swingh_t position to convert.
/// @return The equivilent native horizontal swing position.
uint8_t IRHitachiAc344::convertSwingH(const stdAc::swingh_t position) {
switch (position) {
case stdAc::swingh_t::kAuto: return kHitachiAc344SwingHAuto;
case stdAc::swingh_t::kLeftMax: return kHitachiAc344SwingHLeftMax;
case stdAc::swingh_t::kLeft: return kHitachiAc344SwingHLeft;
case stdAc::swingh_t::kRight: return kHitachiAc344SwingHRight;
case stdAc::swingh_t::kRightMax: return kHitachiAc344SwingHRightMax;
default: return kHitachiAc344SwingHMiddle;
}
}

/// Convert a native horizontal swing postion to it's common equivalent.
/// @param[in] pos A native position to convert.
/// @return The common horizontal swing position.
stdAc::swingh_t IRHitachiAc344::toCommonSwingH(const uint8_t pos) {
switch (pos) {
case kHitachiAc344SwingHLeftMax: return stdAc::swingh_t::kLeftMax;
case kHitachiAc344SwingHLeft: return stdAc::swingh_t::kLeft;
case kHitachiAc344SwingHRight: return stdAc::swingh_t::kRight;
case kHitachiAc344SwingHRightMax: return stdAc::swingh_t::kRightMax;
case kHitachiAc344SwingHAuto: return stdAc::swingh_t::kAuto;
default: return stdAc::swingh_t::kOff;
}
}

/// Convert the current A/C state to its common stdAc::state_t equivalent.
/// @return A stdAc::state_t state.
stdAc::state_t IRHitachiAc344::toCommon(void) {
stdAc::state_t result = IRHitachiAc424::toCommon();
result.protocol = decode_type_t::HITACHI_AC344;
result.swingv = getSwingV() ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
result.swingh = toCommonSwingH(getSwingH());
return result;
}

/// Convert the internal state into a human readable string.
/// @return A string containing the settings in human-readable form.
String IRHitachiAc344::toString(void) {
String result;
result.reserve(120); // Reserve some heap for the string to reduce fragging.
result += _toString();
result += addBoolToString(getSwingV(), kSwingVStr);
result += addIntToString(getSwingH(), kSwingHStr);
result += kSpaceLBraceStr;
switch (getSwingH()) {
case kHitachiAc344SwingHLeftMax: result += kLeftMaxStr; break;
case kHitachiAc344SwingHLeft: result += kLeftStr; break;
case kHitachiAc344SwingHMiddle: result += kMiddleStr; break;
case kHitachiAc344SwingHRight: result += kRightStr; break;
case kHitachiAc344SwingHRightMax: result += kRightMaxStr; break;
case kHitachiAc344SwingHAuto: result += kAutoStr; break;
default: result += kUnknownStr;
}
result += ')';
return result;
}
28 changes: 27 additions & 1 deletion src/ir_Hitachi.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
// Brand: Hitachi, Model: PC-LH3B (HITACHI_AC3)
// Brand: Hitachi, Model: KAZE-312KSDP A/C (HITACHI_AC1)
// Brand: Hitachi, Model: R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1)
// Brand: Hitachi, Model: RAS-22NK remote (HITACHI_AC344)
// Brand: Hitachi, Model: RAS-22NK A/C (HITACHI_AC344)
// Brand: Hitachi, Model: RF11T1 remote (HITACHI_AC344)

#ifndef IR_HITACHI_H_
#define IR_HITACHI_H_
Expand Down Expand Up @@ -52,11 +53,13 @@ const uint8_t kHitachiAc424ButtonFan = 0x42;
const uint8_t kHitachiAc424ButtonTempDown = 0x43;
const uint8_t kHitachiAc424ButtonTempUp = 0x44;
const uint8_t kHitachiAc424ButtonSwingV = 0x81;
const uint8_t kHitachiAc424ButtonSwingH = 0x8C;
const uint8_t kHitachiAc344ButtonPowerMode = kHitachiAc424ButtonPowerMode;
const uint8_t kHitachiAc344ButtonFan = kHitachiAc424ButtonFan;
const uint8_t kHitachiAc344ButtonTempDown = kHitachiAc424ButtonTempDown;
const uint8_t kHitachiAc344ButtonTempUp = kHitachiAc424ButtonTempUp;
const uint8_t kHitachiAc344ButtonSwingV = kHitachiAc424ButtonSwingV;
const uint8_t kHitachiAc344ButtonSwingH = kHitachiAc424ButtonSwingH;

// Byte[13]
const uint8_t kHitachiAc424TempByte = 13;
Expand Down Expand Up @@ -99,6 +102,21 @@ const uint8_t kHitachiAc424PowerByte = 27;
const uint8_t kHitachiAc424PowerOn = 0xF1;
const uint8_t kHitachiAc424PowerOff = 0xE1;

// Byte[35]
const uint8_t kHitachiAc344SwingHByte = 35;
const uint8_t kHitachiAc344SwingHOffset = 0; // Mask 0b00000xxx
const uint8_t kHitachiAc344SwingHSize = 3; // Mask 0b00000xxx
const uint8_t kHitachiAc344SwingHAuto = 0; // 0b000
const uint8_t kHitachiAc344SwingHRightMax = 1; // 0b001
const uint8_t kHitachiAc344SwingHRight = 2; // 0b010
const uint8_t kHitachiAc344SwingHMiddle = 3; // 0b011
const uint8_t kHitachiAc344SwingHLeft = 4; // 0b100
const uint8_t kHitachiAc344SwingHLeftMax = 5; // 0b101

// Byte[37]
const uint8_t kHitachiAc344SwingVByte = 37;
const uint8_t kHitachiAc344SwingVOffset = 5; // Mask 0b00x00000

// HitachiAc1
// Byte[3] (Model)
const uint8_t kHitachiAc1ModelByte = 3;
Expand Down Expand Up @@ -317,6 +335,7 @@ class IRHitachiAc424 {
// The state of the IR remote in IR code form.
uint8_t remote_state[kHitachiAc424StateLength];
void setInvertedStates(void);
String _toString(void);
uint8_t _previoustemp;
};

Expand Down Expand Up @@ -359,6 +378,13 @@ class IRHitachiAc344: public IRHitachiAc424 {
#if SEND_HITACHI_AC344
void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC344
void setSwingV(const bool on);
bool getSwingV(void);
void setSwingH(const uint8_t position);
uint8_t getSwingH(void);
static uint8_t convertSwingH(const stdAc::swingh_t position);
static stdAc::swingh_t toCommonSwingH(const uint8_t pos);
String toString(void);
};

#endif // IR_HITACHI_H_
2 changes: 1 addition & 1 deletion src/ir_MitsubishiHeavy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ stdAc::fanspeed_t IRMitsubishiHeavy152Ac::toCommonFanSpeed(const uint8_t spd) {
}
}

// Convert a native vertical swing to it's common equivalent.
// Convert a native horizontal swing to it's common equivalent.
stdAc::swingh_t IRMitsubishiHeavy152Ac::toCommonSwingH(const uint8_t pos) {
switch (pos) {
case kMitsubishiHeavy152SwingHLeftMax: return stdAc::swingh_t::kLeftMax;
Expand Down
38 changes: 20 additions & 18 deletions test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,49 +773,51 @@ TEST(TestIRac, Hitachi344) {
IRHitachiAc344 ac(kGpioUnused);
IRac irac(kGpioUnused);
IRrecv capture(kGpioUnused);
char expected[] =
char expected_swingon[] =
"Power: On, Mode: 6 (Heat), Temp: 25C, Fan: 6 (Max), "
"Swing(V) Toggle: Off, Button: 19 (Power/Mode)";
char expected_swingv[] =
"Power: On, Mode: 3 (Cool), Temp: 26C, Fan: 1 (Min), "
"Swing(V) Toggle: On, Button: 129 (Swing(V))";
"Button: 129 (Swing(V)), Swing(V): Off, Swing(H): 2 (Right)";

ac.begin();
irac.hitachi344(&ac,
true, // Power
stdAc::opmode_t::kHeat, // Mode
25, // Celsius
stdAc::fanspeed_t::kMax, // Fan speed
stdAc::swingv_t::kOff); // Swing(V)
stdAc::swingv_t::kAuto, // Swing(V)
stdAc::swingh_t::kRight); // Swing(H)

ASSERT_EQ(expected, ac.toString());
ASSERT_EQ(expected_swingon, ac.toString());
ac._irsend.makeDecodeResult();
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
ASSERT_EQ(HITACHI_AC344, ac._irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc344Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
EXPECT_EQ(decode_type_t::HITACHI_AC344, r.protocol);
EXPECT_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
EXPECT_EQ(25, r.degrees);

char expected_swingoff[] =
"Power: On, Mode: 6 (Heat), Temp: 25C, Fan: 6 (Max), "
"Button: 19 (Power/Mode), Swing(V): Off, Swing(H): 2 (Right)";

ac._irsend.reset();
irac.hitachi344(&ac,
true, // Power
stdAc::opmode_t::kCool, // Mode
26, // Celsius
stdAc::fanspeed_t::kMin, // Fan speed
stdAc::swingv_t::kAuto); // Swing(V)

ASSERT_EQ(expected_swingv, ac.toString());
stdAc::opmode_t::kHeat, // Mode
25, // Celsius
stdAc::fanspeed_t::kMax, // Fan speed
stdAc::swingv_t::kOff, // Swing(V)
stdAc::swingh_t::kRight); // Swing(H)
ASSERT_EQ(expected_swingoff, ac.toString());
ac._irsend.makeDecodeResult();
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
ASSERT_EQ(HITACHI_AC344, ac._irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc344Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected_swingv, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(expected_swingoff,
IRAcUtils::resultAcToString(&ac._irsend.capture));
}

TEST(TestIRac, Hitachi424) {
Expand All @@ -824,10 +826,10 @@ TEST(TestIRac, Hitachi424) {
IRrecv capture(0);
char expected[] =
"Power: On, Mode: 6 (Heat), Temp: 25C, Fan: 6 (Max), "
"Swing(V) Toggle: Off, Button: 19 (Power/Mode)";
"Button: 19 (Power/Mode), Swing(V) Toggle: Off";
char expected_swingv[] =
"Power: On, Mode: 3 (Cool), Temp: 26C, Fan: 1 (Min), "
"Swing(V) Toggle: On, Button: 129 (Swing(V))";
"Button: 129 (Swing(V)), Swing(V) Toggle: On";

ac.begin();
irac.hitachi424(&ac,
Expand Down
Loading

0 comments on commit c56b9cd

Please sign in to comment.