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

[ELECTRA_AC] Add support for "IFeel" & Sensor settings. #1645

Merged
merged 2 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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());
}