Skip to content

Commit

Permalink
[ELECTRA_AC] Add support for "IFeel" setting.
Browse files Browse the repository at this point in the history
* Add `(set|get)IFeel()` & `(set|get)IFeelTemp()` methods.
* Add and update Unit test coverage.

For #1644

Co-Authored-By: @Aculeasis
  • Loading branch information
crankyoldgit committed Oct 20, 2021
1 parent 429c9fa commit 3909982
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 14 deletions.
42 changes: 40 additions & 2 deletions src/ir_Electra.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018, 2019 David Conran
// Copyright 2018-2021 David Conran
/// @file
/// @brief Support for Electra A/C protocols.
/// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp
Expand Down Expand Up @@ -310,6 +310,37 @@ bool IRElectraAc::getTurbo(void) const {
return _.Turbo;
}

/// Get the IFeel mode of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRElectraAc::getIFeel(void) const { return _.IFeel; }

/// Set the IFeel mode of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRElectraAc::setIFeel(const bool on) {
_.IFeel = on;
if (_.IFeel)
// Make sure there is a reasonable value in _.IFeelTemp
setIFeelTemp(getIFeelTemp());
else
// Clear any previous stored temp..
_.IFeelTemp = kElectraAcIFeelMinTemp;
}

/// Set the temperature for the IFeel mode.
/// @param[in] temp The temperature in degrees celsius.
void IRElectraAc::setIFeelTemp(const uint8_t temp) {
_.IFeelTemp = std::min(kElectraAcIFeelMaxTemp,
std::max(kElectraAcIFeelMinTemp, temp)) +
kElectraAcIFeelTempDelta;
}

/// Get the current temperature setting for the IFeel mode.
/// @return The current setting for temp. in degrees celsius.
uint8_t IRElectraAc::getIFeelTemp(void) const {
return std::max(kElectraAcIFeelTempDelta, _.IFeelTemp) -
kElectraAcIFeelTempDelta;
}

/// Convert the current internal state into its stdAc::state_t equivalent.
/// @return The stdAc equivalent of the native settings.
stdAc::state_t IRElectraAc::toCommon(void) const {
Expand Down Expand Up @@ -342,7 +373,7 @@ stdAc::state_t IRElectraAc::toCommon(void) const {
/// @return A human readable string.
String IRElectraAc::toString(void) const {
String result = "";
result.reserve(130); // Reserve some heap for the string to reduce fragging.
result.reserve(160); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(_.Power, kPowerStr, false);
result += addModeToString(_.Mode, kElectraAcAuto, kElectraAcCool,
kElectraAcHeat, kElectraAcDry, kElectraAcFan);
Expand All @@ -355,6 +386,13 @@ String IRElectraAc::toString(void) const {
result += addToggleToString(getLightToggle(), kLightStr);
result += addBoolToString(_.Clean, kCleanStr);
result += addBoolToString(_.Turbo, kTurboStr);
result += addBoolToString(_.IFeel, kIFeelStr);
if (_.IFeel) {
result += kCommaSpaceStr;
result += kIFeelStr;
result += ' ';
result += addTempToString(getIFeelTemp(), true, false);
}
return result;
}

Expand Down
21 changes: 18 additions & 3 deletions src/ir_Electra.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019 David Conran
// Copyright 2019-2021 David Conran
/// @file
/// @brief Support for Electra A/C protocols.
/// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp
Expand All @@ -9,6 +9,10 @@
// Brand: Electra, Model: Classic INV 17 / AXW12DCS A/C
// Brand: Electra, Model: YKR-M/003E remote
// Brand: Frigidaire, Model: FGPC102AB1 A/C
// Brand: Subtropic, Model: SUB-07HN1_18Y A/C
// Brand: Subtropic, Model: YKR-H/102E remote
// Brand: Centek, Model: SCT-65Q09 A/C
// Brand: Centek, Model: YKR-P/002E remote

#ifndef IR_ELECTRA_H_
#define IR_ELECTRA_H_
Expand Down Expand Up @@ -46,10 +50,12 @@ union ElectraProtocol {
uint8_t Turbo :1;
uint8_t :1;
// Byte 6
uint8_t :5;
uint8_t :3;
uint8_t IFeel :1;
uint8_t :1;
uint8_t Mode :3;
// Byte 7
uint8_t :8;
uint8_t IFeelTemp :8;
// Byte 8
uint8_t :8;
// Byte 9
Expand Down Expand Up @@ -93,6 +99,11 @@ const uint8_t kElectraAcLightToggleMask = 0x11;
// and known OFF values of 0x08 (0b00001000) & 0x05 (0x00000101)
const uint8_t kElectraAcLightToggleOff = 0x08;

// Re: Byte[7]. Or Delta == 0xA and Temperature are stored in last 6 bits,
// and bit 7 stores Unknown flag
const uint8_t kElectraAcIFeelTempDelta = 0x4A;
const uint8_t kElectraAcIFeelMinTemp = 0; // 0C
const uint8_t kElectraAcIFeelMaxTemp = 50; // 50C

// Classes
/// Class for handling detailed Electra A/C messages.
Expand Down Expand Up @@ -130,6 +141,10 @@ class IRElectraAc {
bool getLightToggle(void) const;
void setTurbo(const bool on);
bool getTurbo(void) const;
void setIFeel(const bool on);
bool getIFeel(void) const;
void setIFeelTemp(const uint8_t temp);
uint8_t getIFeelTemp(void) const;
uint8_t* getRaw(void);
void setRaw(const uint8_t new_code[],
const uint16_t length = kElectraAcStateLength);
Expand Down
3 changes: 2 additions & 1 deletion test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,8 @@ TEST(TestIRac, Electra) {
IRrecv capture(kGpioUnused);
char expected[] =
"Power: On, Mode: 6 (Fan), Temp: 26C, Fan: 1 (High), "
"Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On";
"Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On, "
"IFeel: Off";

ac.begin();
irac.electra(&ac,
Expand Down
69 changes: 61 additions & 8 deletions test/ir_Electra_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ TEST(TestDecodeElectraAC, RealExampleDecode) {
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
"IFeel: Off",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
Expand Down Expand Up @@ -235,23 +236,26 @@ TEST(TestIRElectraAcClass, HumanReadable) {
ac.setRaw(on_cool_32C_auto_voff);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 32C, Fan: 5 (Auto), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
"IFeel: Off",
ac.toString());
uint8_t on_cool_16C_auto_voff[13] = {
0xC3, 0x47, 0xE0, 0x00, 0xA0, 0x00, 0x20,
0x00, 0x00, 0x20, 0x00, 0x41, 0x0B};
ac.setRaw(on_cool_16C_auto_voff);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 5 (Auto), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
"IFeel: Off",
ac.toString());
uint8_t on_cool_16C_low_voff[13] = {
0xC3, 0x47, 0xE0, 0x00, 0x60, 0x00, 0x20,
0x00, 0x00, 0x20, 0x00, 0x41, 0xCB};
ac.setRaw(on_cool_16C_low_voff);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
"IFeel: Off",
ac.toString());
}

Expand All @@ -275,7 +279,8 @@ TEST(TestIRElectraAcClass, Clean) {
ac.setRaw(on);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
"IFeel: Off",
ac.toString());
}

Expand All @@ -301,7 +306,8 @@ TEST(TestIRElectraAcClass, Turbo) {
ac.setRaw(on);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On",
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On, "
"IFeel: Off",
ac.toString());
}

Expand All @@ -325,7 +331,8 @@ TEST(TestIRElectraAcClass, LightToggle) {
ac.setRaw(on);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
"IFeel: Off",
ac.toString());
}

Expand All @@ -352,8 +359,54 @@ TEST(TestIRElectraAcClass, ConstructKnownState) {

EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off",
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
"IFeel: Off",
ac.toString());
EXPECT_STATE_EQ(on_cool_24C_fan1_swing_off_turbo_off_clean_on,
ac.getRaw(), kElectraAcBits);
}

TEST(TestIRElectraAcClass, IFeel) {
IRElectraAc ac(kGpioUnused);
ac.stateReset();
// Test a real example.
const uint8_t ifeel_on[kElectraAcStateLength] = {
0xC3, 0x6F, 0xE0, 0x00, 0xA0, 0x00, 0x28,
0x64, 0x00, 0x20, 0x00, 0x1E, 0x7C};
ac.setRaw(ifeel_on);
EXPECT_TRUE(ac.getIFeel());
EXPECT_EQ(26, ac.getIFeelTemp());
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 5 (Auto), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
"IFeel: On, IFeel Temp: 26C",
ac.toString());

ac.stateReset();
EXPECT_FALSE(ac.getIFeel());
EXPECT_EQ(kElectraAcIFeelMinTemp, ac.getIFeelTemp());

ac.setIFeel(true);
EXPECT_TRUE(ac.getIFeel());
EXPECT_EQ(kElectraAcIFeelMinTemp, ac.getIFeelTemp());

ac.setIFeelTemp(kElectraAcIFeelMaxTemp);
EXPECT_EQ(kElectraAcIFeelMaxTemp, ac.getIFeelTemp());

ac.setIFeelTemp(kElectraAcIFeelMaxTemp + 1);
EXPECT_EQ(kElectraAcIFeelMaxTemp, ac.getIFeelTemp());

ac.setIFeel(false);
EXPECT_FALSE(ac.getIFeel());
EXPECT_EQ(kElectraAcIFeelMinTemp, ac.getIFeelTemp());
EXPECT_EQ(0, ac._.IFeelTemp);

ac.setIFeel(true);
ac.setIFeelTemp(kElectraAcIFeelMinTemp);
EXPECT_TRUE(ac.getIFeel());
EXPECT_EQ(kElectraAcIFeelMinTemp, ac.getIFeelTemp());

ac.setIFeelTemp(26); // Celsius
EXPECT_TRUE(ac.getIFeel());
EXPECT_EQ(26, ac.getIFeelTemp());
}

0 comments on commit 3909982

Please sign in to comment.