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

TOSHIBA_AC: Add Filter setting support. aka. Pure. #1693

Merged
merged 3 commits into from
Nov 29, 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
7 changes: 4 additions & 3 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2158,11 +2158,12 @@ void IRac::teco(IRTecoAc *ac,
/// @param[in] swingv The vertical swing setting.
/// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] econo Run the device in economical mode.
/// @param[in] filter Turn on the (Pure/ion/pollen/etc) filter mode.
void IRac::toshiba(IRToshibaAC *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const bool turbo, const bool econo) {
const bool turbo, const bool econo, const bool filter) {
ac->begin();
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
Expand All @@ -2175,7 +2176,7 @@ void IRac::toshiba(IRToshibaAC *ac,
ac->setTurbo(turbo);
ac->setEcono(econo);
// No Light setting available.
// No Filter setting available.
ac->setFilter(filter);
// No Clean setting available.
// No Beep setting available.
// No Sleep setting available.
Expand Down Expand Up @@ -3114,7 +3115,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
{
IRToshibaAC ac(_pin, _inverted, _modulation);
toshiba(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.turbo, send.econo);
send.turbo, send.econo, send.filter);
break;
}
#endif // SEND_TOSHIBA_AC
Expand Down
2 changes: 1 addition & 1 deletion src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ void electra(IRElectraAc *ac,
void toshiba(IRToshibaAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool turbo, const bool econo);
const bool turbo, const bool econo, const bool filter);
#endif // SEND_TOSHIBA_AC
#if SEND_TROTEC
void trotec(IRTrotecESP *ac,
Expand Down
22 changes: 17 additions & 5 deletions src/ir_Toshiba.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,7 @@ void IRToshibaAC::setTemp(const uint8_t degrees) {

/// Get the current temperature setting.
/// @return The current setting for temp. in degrees celsius.
uint8_t IRToshibaAC::getTemp(void) const {
return _.Temp + kToshibaAcMinTemp;
}
uint8_t IRToshibaAC::getTemp(void) const { return _.Temp + kToshibaAcMinTemp; }

/// Set the speed of the fan.
/// @param[in] speed The desired setting (0 is Auto, 1-5 is the speed, 5 is Max)
Expand Down Expand Up @@ -339,6 +337,19 @@ void IRToshibaAC::setEcono(const bool on) {
}
}

/// Get the filter (Pure/Ion Filter) setting of the A/C.
/// @return true, if the current setting is on. Otherwise, false.
bool IRToshibaAC::getFilter(void) const {
return (getStateLength() >= kToshibaACStateLength) ? _.Filter : false;
}

/// Set the filter (Pure/Ion Filter) setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRToshibaAC::setFilter(const bool on) {
_.Filter = on;
if (on) setStateLength(std::min(kToshibaACStateLength, getStateLength()));
}

/// 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.
Expand Down Expand Up @@ -421,6 +432,7 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const {
result.fanspeed = toCommonFanSpeed(getFan());
result.turbo = getTurbo();
result.econo = getEcono();
result.filter = getFilter();
}
switch (getSwing()) {
case kToshibaAcSwingOn:
Expand All @@ -436,7 +448,6 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const {
}
// Not supported.
result.light = false;
result.filter = false;
result.swingh = stdAc::swingh_t::kOff;
result.quiet = false;
result.clean = false;
Expand All @@ -450,7 +461,7 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const {
/// @return A human readable string.
String IRToshibaAC::toString(void) const {
String result = "";
result.reserve(80);
result.reserve(95);
result += addTempToString(getTemp(), true, false);
switch (getStateLength()) {
case kToshibaACStateLengthShort:
Expand All @@ -477,6 +488,7 @@ String IRToshibaAC::toString(void) const {
kToshibaAcFanMed);
result += addBoolToString(getTurbo(), kTurboStr);
result += addBoolToString(getEcono(), kEconoStr);
result += addBoolToString(getFilter(), kFilterStr);
}
return result;
}
Expand Down
38 changes: 23 additions & 15 deletions src/ir_Toshiba.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/// @see https://docs.google.com/spreadsheets/d/1yidE2fvaO9kpCHfKafIdH31q4uaskYR1OwwrkyOxbp0/edit?usp=drivesdk
/// @see https://www.toshiba-carrier.co.jp/global/about/index.htm
/// @see http://www.toshiba-carrier.co.th/AboutUs/Pages/CompanyProfile.aspx
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1692

// Supports:
// Brand: Toshiba, Model: RAS-B13N3KV2
Expand All @@ -18,6 +19,8 @@
// Brand: Toshiba, Model: WC-L03SE
// Brand: Toshiba, Model: WH-UB03NJ remote
// Brand: Toshiba, Model: RAS-2558V A/C
// Brand: Toshiba, Model: WH-TA01JE remote
// Brand: Toshiba, Model: RAS-25SKVP2-ND A/C
// Brand: Carrier, Model: 42NQV060M2 / 38NYV060M2 A/C
// Brand: Carrier, Model: 42NQV050M2 / 38NYV050M2 A/C
// Brand: Carrier, Model: 42NQV035M2 / 38NYV035M2 A/C
Expand Down Expand Up @@ -50,28 +53,31 @@ union ToshibaProtocol{
///< 1 (56 bit message)
///< 3 (72 bit message)
///< 4 (80 bit message)
uint8_t Length :8;
uint8_t Length :8;
// Byte[3] - The bit-inverted value of the "length" byte.
uint8_t :8;
uint8_t :8;
// Byte[4]
uint8_t :3;
uint8_t LongMsg :1;
uint8_t :1;
uint8_t ShortMsg:1;
uint8_t :2;
uint8_t :3;
uint8_t LongMsg :1;
uint8_t :1;
uint8_t ShortMsg :1;
uint8_t :2;
// Byte[5]
uint8_t Swing :3;
uint8_t :1;
uint8_t Temp :4;
uint8_t Swing :3;
uint8_t :1;
uint8_t Temp :4;
// Byte[6]
uint8_t Mode :3;
uint8_t :2;
uint8_t Fan :3;
uint8_t Mode :3;
uint8_t :2;
uint8_t Fan :3;
// Byte[7]
uint8_t :8;
uint8_t :4;
uint8_t Filter :1;
uint8_t :3;

// Byte[8]
// (Checksum for 72 bit messages, Eco/Turbo for long 80 bit messages)
uint8_t EcoTurbo :8;
uint8_t EcoTurbo :8;
};
};

Expand Down Expand Up @@ -144,6 +150,8 @@ class IRToshibaAC {
bool getTurbo(void) const;
void setEcono(const bool on);
bool getEcono(void) const;
void setFilter(const bool on);
bool getFilter(void) const;
void setMode(const uint8_t mode);
uint8_t getMode(const bool raw = false) const;
void setRaw(const uint8_t newState[],
Expand Down
16 changes: 10 additions & 6 deletions test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1989,7 +1989,7 @@ TEST(TestIRac, Toshiba) {
IRrecv capture(kGpioUnused);
char expected[] =
"Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), "
"Turbo: Off, Econo: On";
"Turbo: Off, Econo: On, Filter: Off";

ac.begin();
irac.toshiba(&ac,
Expand All @@ -1999,7 +1999,8 @@ TEST(TestIRac, Toshiba) {
stdAc::fanspeed_t::kLow, // Fan speed
stdAc::swingv_t::kOff, // Vertical Swing
false, // Turbo
true); // Econo
true, // Econo
false); // Filter
ASSERT_EQ(expected, ac.toString());
ASSERT_EQ(kToshibaACStateLengthLong, ac.getStateLength());
ac._irsend.makeDecodeResult();
Expand Down Expand Up @@ -2904,7 +2905,7 @@ TEST(TestIRac, Issue1250) {
// Now send the state so we can actually decode/capture what we sent.
char expected_on[] =
"Temp: 19C, Power: On, Mode: 4 (Fan), Fan: 0 (Auto), "
"Turbo: Off, Econo: Off";
"Turbo: Off, Econo: Off, Filter: Off";
ac._irsend.reset();
irac.toshiba(&ac,
irac.next.power, // Power
Expand All @@ -2913,7 +2914,8 @@ TEST(TestIRac, Issue1250) {
irac.next.fanspeed, // Fan speed
irac.next.swingv, // Vertical Swing
irac.next.turbo, // Turbo
irac.next.econo); // Econo
irac.next.econo, // Econo
irac.next.filter); // Filter
ASSERT_EQ(expected_on, ac.toString());
ASSERT_EQ(kToshibaACStateLength, ac.getStateLength());
ac._irsend.makeDecodeResult();
Expand All @@ -2929,7 +2931,8 @@ TEST(TestIRac, Issue1250) {
irac.sendAc();
// Now send the state so we can actually decode/capture what we sent.
char expected_off[] =
"Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off";
"Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, "
"Filter: Off";
ac._irsend.reset();
irac.toshiba(&ac,
irac.next.power, // Power
Expand All @@ -2938,7 +2941,8 @@ TEST(TestIRac, Issue1250) {
irac.next.fanspeed, // Fan speed
irac.next.swingv, // Vertical Swing
irac.next.turbo, // Turbo
irac.next.econo); // Econo
irac.next.econo, // Econo
irac.next.filter); // Filter
ASSERT_EQ(expected_off, ac.toString());
ASSERT_EQ(kToshibaACStateLength, ac.getStateLength());
ac._irsend.makeDecodeResult();
Expand Down
52 changes: 43 additions & 9 deletions test/ir_Toshiba_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,20 +312,21 @@ TEST(TestToshibaACClass, HumanReadableOutput) {

ac.setRaw(initial_state);
EXPECT_EQ("Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), "
"Turbo: Off, Econo: Off",
"Turbo: Off, Econo: Off, Filter: Off",
ac.toString());
ac.setRaw(modified_state);
EXPECT_EQ("Temp: 17C, Power: On, Mode: 1 (Cool), Fan: 5 (High), "
"Turbo: Off, Econo: Off",
"Turbo: Off, Econo: Off, Filter: Off",
ac.toString());
ac.setTemp(25);
ac.setFan(3);
ac.setMode(kToshibaAcDry);
EXPECT_EQ("Temp: 25C, Power: On, Mode: 2 (Dry), Fan: 3 (Medium), "
"Turbo: Off, Econo: Off",
"Turbo: Off, Econo: Off, Filter: Off",
ac.toString());
ac.off();
EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off",
EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off, "
"Filter: Off",
ac.toString());
}

Expand Down Expand Up @@ -379,7 +380,7 @@ TEST(TestDecodeToshibaAC, SyntheticExample) {
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, "
"Econo: Off",
"Econo: Off, Filter: Off",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
Expand Down Expand Up @@ -555,6 +556,7 @@ TEST(TestToshibaACClass, toCommon) {
ac.setMode(kToshibaAcCool);
ac.setTemp(20);
ac.setFan(kToshibaAcFanMax);
ac.setFilter(true);
// Now test it.
ASSERT_EQ(decode_type_t::TOSHIBA_AC, ac.toCommon().protocol);
ASSERT_EQ(-1, ac.toCommon().model);
Expand All @@ -563,13 +565,13 @@ TEST(TestToshibaACClass, toCommon) {
ASSERT_EQ(20, ac.toCommon().degrees);
ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode);
ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed);
ASSERT_TRUE(ac.toCommon().filter);
// Unsupported.
ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv);
ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh);
ASSERT_FALSE(ac.toCommon().turbo);
ASSERT_FALSE(ac.toCommon().econo);
ASSERT_FALSE(ac.toCommon().light);
ASSERT_FALSE(ac.toCommon().filter);
ASSERT_FALSE(ac.toCommon().clean);
ASSERT_FALSE(ac.toCommon().beep);
ASSERT_FALSE(ac.toCommon().quiet);
Expand Down Expand Up @@ -626,7 +628,7 @@ TEST(TestDecodeToshibaAC, RealLongExample) {
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 22C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: On, "
"Econo: Off",
"Econo: Off, Filter: Off",
IRAcUtils::resultAcToString(&irsend.capture));
}

Expand Down Expand Up @@ -731,7 +733,7 @@ TEST(TestToshibaACClass, ConstructLongState) {
ac.setEcono(true);
EXPECT_EQ(
"Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), "
"Turbo: Off, Econo: On",
"Turbo: Off, Econo: On, Filter: Off",
ac.toString());
EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength());
const uint8_t expectedState[kToshibaACStateLengthLong] = {
Expand Down Expand Up @@ -781,7 +783,8 @@ TEST(TestDecodeToshibaAC, RealExample_WHUB03NJ) {
EXPECT_EQ(kToshibaACBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off",
"Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, "
"Filter: Off",
IRAcUtils::resultAcToString(&irsend.capture));
}

Expand Down Expand Up @@ -828,3 +831,34 @@ TEST(TestToshibaACClass, SwingCodes) {
"Temp: 17C, Swing(V): 4 (Toggle)",
ac.toString());
}

// For https://github.com/crankyoldgit/IRremoteESP8266/issues/1692
TEST(TestToshibaACClass, Filter) {
IRToshibaAC ac(kGpioUnused);
ac.begin();
EXPECT_FALSE(ac.getFilter());

ac.setFilter(true);
EXPECT_TRUE(ac.getFilter());


ac.setFilter(false);
EXPECT_FALSE(ac.getFilter());

ac.setFilter(true);
EXPECT_TRUE(ac.getFilter());

const uint8_t pure_off[kToshibaACStateLength] = {
0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x40, 0x03, 0x00, 0x42};
ac.setRaw(pure_off);
EXPECT_FALSE(ac.getFilter());

const uint8_t pure_on[kToshibaACStateLength] = {
0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x40, 0x03, 0x10, 0x52};
ac.setRaw(pure_on);
EXPECT_TRUE(ac.getFilter());

// Convert a known filter/pure on state to a known off filter/pure state.
ac.setFilter(false);
EXPECT_STATE_EQ(pure_off, ac.getRaw(), ac.getStateLength() * 8);
}