Skip to content

Commit

Permalink
Panasonic AC: Add Ion Filter support for DKE models. (#1025)
Browse files Browse the repository at this point in the history
* Panasonic AC: Add Ion Filter support for DKE models.
* Add set/getIon()
* Handle model specifics as it is confirmed only on DKE.
* Add and update unit tests accordingly.
* Update Common A/C API for panasonic.
* Update supported model info

Fixes #1024
  • Loading branch information
crankyoldgit authored Jan 29, 2020
1 parent fa97474 commit 5c931e0
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 16 deletions.
4 changes: 2 additions & 2 deletions SupportedProtocols.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--- WARNING: Do NOT edit this file directly.
It is generated by './tools/scrape_supported_devices.py'.
Last generated: Mon Jan 27 05:43:44 2020 --->
Last generated: Wed Jan 29 18:27:29 2020 --->
# IR Protocols supported by this library

| Protocol | Brand | Model | A/C Model | Detailed A/C Support |
Expand Down Expand Up @@ -49,7 +49,7 @@
| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Yamaha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | RAV561 remote<BR>RXV585B A/V Receiver | | - |
| [Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.cpp) | **[Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.h)** | NS-09AHTI A/C<BR>NS-09AHTI A/C<BR>ZH/TY-01 remote<BR>ZH/TY-01 remote | | Yes |
| [Nikai](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Nikai.cpp) | **Unknown** | | | - |
| [Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)<BR>A75C3704 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>CKP series A/C<BR>CS-E7PKR A/C (Use DKE)<BR>CS-ME10CKPG A/C<BR>CS-ME12CKPG A/C<BR>CS-ME14CKPG A/C<BR>CS-YW9MKD A/C<BR>CS-Z9RKR A/C<BR>DKE series A/C<BR>JKE series A/C<BR>NKE series A/C<BR>PKR series A/C (Use DKE)<BR>RKR series A/C<BR>TV | CKP<BR>DKE<BR>JKE<BR>LKE<BR>NKE<BR>RKR | Yes |
| [Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)<BR>A75C2616-1 remote (DKE)<BR>A75C3704 remote<BR>A75C3747 remote<BR>CKP series A/C<BR>CS-E7PKR A/C (DKE)<BR>CS-ME10CKPG A/C<BR>CS-ME12CKPG A/C<BR>CS-ME14CKPG A/C<BR>CS-YW9MKD A/C<BR>CS-Z9RKR A/C<BR>DKE series A/C<BR>DKW series A/C (DKE)<BR>JKE series A/C<BR>NKE series A/C<BR>PKR series A/C (DKE)<BR>RKR series A/C<BR>TV | CKP<BR>DKE<BR>JKE<BR>LKE<BR>NKE<BR>RKR | Yes |
| [Pioneer](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pioneer.cpp) | **Unknown** | | | - |
| [Pronto](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pronto.cpp) | **Unknown** | | | - |
| [RC5_RC6](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Unknown** | | | - |
Expand Down
5 changes: 3 additions & 2 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,8 @@ void IRac::panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const int16_t clock) {
const bool quiet, const bool turbo, const bool filter,
const int16_t clock) {
ac->begin();
ac->setModel(model);
ac->setPower(on);
Expand All @@ -951,9 +952,9 @@ void IRac::panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
ac->setSwingHorizontal(ac->convertSwingH(swingh));
ac->setQuiet(quiet);
ac->setPowerful(turbo);
ac->setIon(filter);
// No Light setting available.
// No Econo setting available.
// No Filter setting available.
// No Clean setting available.
// No Beep setting available.
// No Sleep setting available.
Expand Down
3 changes: 2 additions & 1 deletion src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@ void electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const int16_t clock = -1);
const bool quiet, const bool turbo, const bool filter,
const int16_t clock = -1);
#endif // SEND_PANASONIC_AC
#if SEND_SAMSUNG_AC
void samsung(IRSamsungAc *ac,
Expand Down
22 changes: 21 additions & 1 deletion src/ir_Panasonic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) {
default:
break;
}
// Reset the Ion filter.
setIon(getIon());
}

panasonic_ac_remote_model_t IRPanasonicAc::getModel(void) {
Expand Down Expand Up @@ -589,6 +591,22 @@ bool IRPanasonicAc::isOffTimerEnabled(void) {
return GETBIT8(remote_state[13], kPanasonicAcOffTimerOffset);
}

bool IRPanasonicAc::getIon(void) {
switch (this->getModel()) {
case kPanasonicDke:
return GETBIT8(remote_state[kPanasonicAcIonFilterByte],
kPanasonicAcIonFilterOffset);
default:
return false;
}
}

void IRPanasonicAc::setIon(const bool on) {
if (this->getModel() == kPanasonicDke)
setBit(&remote_state[kPanasonicAcIonFilterByte],
kPanasonicAcIonFilterOffset, on);
}

// Convert a standard A/C mode into its native mode.
uint8_t IRPanasonicAc::convertMode(const stdAc::opmode_t mode) {
switch (mode) {
Expand Down Expand Up @@ -693,10 +711,10 @@ stdAc::state_t IRPanasonicAc::toCommon(void) {
result.swingh = this->toCommonSwingH(this->getSwingHorizontal());
result.quiet = this->getQuiet();
result.turbo = this->getPowerful();
result.filter = this->getIon();
// Not supported.
result.econo = false;
result.clean = false;
result.filter = false;
result.light = false;
result.beep = false;
result.sleep = -1;
Expand Down Expand Up @@ -775,6 +793,8 @@ String IRPanasonicAc::toString(void) {
}
result += addBoolToString(getQuiet(), kQuietStr);
result += addBoolToString(getPowerful(), kPowerfulStr);
if (getModel() == kPanasonicDke)
result += addBoolToString(getIon(), kIonStr);
result += addLabeledString(minsToString(getClock()), kClockStr);
result += addLabeledString(
isOnTimerEnabled() ? minsToString(getOnTimer()) : kOffStr,
Expand Down
20 changes: 12 additions & 8 deletions src/ir_Panasonic.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@
// Brand: Panasonic, Model: TV
// Brand: Panasonic, Model: JKE series A/C
// Brand: Panasonic, Model: DKE series A/C
// Brand: Panasonic, Model: DKW series A/C (DKE)
// Brand: Panasonic, Model: PKR series A/C (DKE)
// Brand: Panasonic, Model: CKP series A/C
// Brand: Panasonic, Model: NKE series A/C
// Brand: Panasonic, Model: RKR series A/C
// Brand: Panasonic, Model: CS-ME10CKPG A/C
// Brand: Panasonic, Model: CS-ME12CKPG A/C
// Brand: Panasonic, Model: CS-ME14CKPG A/C
// Brand: Panasonic, Model: PKR series A/C (Use DKE)
// Brand: Panasonic, Model: CS-E7PKR A/C (Use DKE)
// Brand: Panasonic, Model: RKR series A/C
// Brand: Panasonic, Model: CS-E7PKR A/C (DKE)
// Brand: Panasonic, Model: CS-Z9RKR A/C
// Brand: Panasonic, Model: NKE series A/C
// Brand: Panasonic, Model: CS-YW9MKD A/C
// Brand: Panasonic, Model: A75C3747 remote
// Brand: Panasonic, Model: A75C3704 remote
// Brand: Panasonic, Model: A75C2311 remote (CKP)
// Brand: Panasonic, Model: A75C3747 remote
// Brand: Panasonic, Model: A75C3747 remote
// Brand: Panasonic, Model: A75C2616-1 remote (DKE)
// Brand: Panasonic, Model: A75C3704 remote
// Brand: Panasonic, Model: A75C3747 remote

#ifndef IR_PANASONIC_H_
Expand Down Expand Up @@ -86,6 +85,9 @@ const uint8_t kPanasonicAcTimeOverflowSize = 3; // Bits
const uint16_t kPanasonicAcTimeMax = 23 * 60 + 59; // Mins since midnight.
const uint16_t kPanasonicAcTimeSpecial = 0x600;

const uint8_t kPanasonicAcIonFilterByte = 22; // Byte
const uint8_t kPanasonicAcIonFilterOffset = 0; // Bit

const uint8_t kPanasonicKnownGoodState[kPanasonicAcStateLength] = {
0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
Expand Down Expand Up @@ -123,6 +125,8 @@ class IRPanasonicAc {
bool getQuiet(void);
void setPowerful(const bool on);
bool getPowerful(void);
void setIon(const bool on);
bool getIon(void);
void setModel(const panasonic_ac_remote_model_t model);
panasonic_ac_remote_model_t getModel(void);
void setSwingVertical(const uint8_t elevation);
Expand Down
5 changes: 4 additions & 1 deletion test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ TEST(TestIRac, Panasonic) {
stdAc::swingh_t::kLeft, // Horizontal swing
true, // Quiet
false, // Turbo
false, // Filter
19 * 60 + 17); // Clock
ASSERT_EQ(expected_nke, ac.toString());
ac._irsend.makeDecodeResult();
Expand All @@ -862,7 +863,8 @@ TEST(TestIRac, Panasonic) {
char expected_dke[] =
"Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (High), "
"Swing(V): 2 (High), Swing(H): 6 (Middle), "
"Quiet: Off, Powerful: On, Clock: 19:17, On Timer: Off, Off Timer: Off";
"Quiet: Off, Powerful: On, Ion: On, "
"Clock: 19:17, On Timer: Off, Off Timer: Off";
ac._irsend.reset();
irac.panasonic(&ac,
kPanasonicDke, // Model
Expand All @@ -874,6 +876,7 @@ TEST(TestIRac, Panasonic) {
stdAc::swingh_t::kMiddle, // Horizontal swing
false, // Quiet
true, // Turbo
true, // Filter
19 * 60 + 17); // Clock
ASSERT_EQ(expected_dke, ac.toString());
ac._irsend.makeDecodeResult();
Expand Down
57 changes: 56 additions & 1 deletion test/ir_Panasonic_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,26 @@ TEST(TestIRPanasonicAcClass, QuietAndPowerful) {
EXPECT_FALSE(pana.getPowerful());
}

TEST(TestIRPanasonicAcClass, SetAndGetIon) {
IRPanasonicAc ac(0);
// Ion Filter only works for DKE.
ac.setModel(kPanasonicDke);
ac.setIon(true);
EXPECT_TRUE(ac.getIon());
ac.setIon(false);
EXPECT_FALSE(ac.getIon());
ac.setIon(true);
EXPECT_TRUE(ac.getIon());

// Now try a different (a guess at unsupported) model.
ac.setModel(kPanasonicRkr);
EXPECT_FALSE(ac.getIon());
ac.setIon(true);
EXPECT_FALSE(ac.getIon());
ac.setIon(false);
EXPECT_FALSE(ac.getIon());
}

TEST(TestIRPanasonicAcClass, HumanReadable) {
IRPanasonicAc pana(0);
EXPECT_EQ(
Expand Down Expand Up @@ -767,7 +787,7 @@ TEST(TestIRPanasonicAcClass, HumanReadable) {
EXPECT_EQ(
"Model: 3 (DKE), Power: Off, Mode: 4 (Heat), Temp: 30C, "
"Fan: 4 (High), Swing(V): 15 (Auto), "
"Swing(H): 11 (Right), Quiet: On, Powerful: Off, "
"Swing(H): 11 (Right), Quiet: On, Powerful: Off, Ion: Off, "
"Clock: 00:00, On Timer: Off, Off Timer: Off",
pana.toString());
}
Expand Down Expand Up @@ -1180,3 +1200,38 @@ TEST(TestIRPanasonicAcClass, toCommon) {
ASSERT_EQ(kPanasonicAcSwingVMiddle,
IRPanasonicAc::convertSwingV(stdAc::swingv_t::kMiddle));
}

//
// Test for DKE/DKW model / see issue #1024
TEST(TestDecodePanasonicAC, DkeIonRealMessages) {
IRsendTest irsend(0);
IRrecv irrecv(0);
irsend.begin();

// Data from Issue #1024
// 0x0220E004000000060220E004004F3280AF0D000660000001000630
uint8_t dkeIonOff[kPanasonicAcStateLength] = {
0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
0x20, 0xE0, 0x04, 0x00, 0x4F, 0x32, 0x80, 0xAF, 0x0D,
0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0x00, 0x06, 0x30};

// 0x0220E004000000060220E004004F3280AF0D000660000101000631
uint8_t dkeIonOn[kPanasonicAcStateLength] = {
0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02,
0x20, 0xE0, 0x04, 0x00, 0x4F, 0x32, 0x80, 0xAF, 0x0D,
0x00, 0x06, 0x60, 0x00, 0x01, 0x01, 0x00, 0x06, 0x31};

IRPanasonicAc ac(0);
ac.setRaw(dkeIonOff);
EXPECT_EQ(
"Model: 3 (DKE), Power: On, Mode: 4 (Heat), Temp: 25C, Fan: 7 (Auto), "
"Swing(V): 15 (Auto), Swing(H): 13 (Auto), Quiet: Off, Powerful: Off, "
"Ion: Off, Clock: 00:00, On Timer: 00:00, Off Timer: 00:00",
ac.toString());
ac.setRaw(dkeIonOn);
EXPECT_EQ(
"Model: 3 (DKE), Power: On, Mode: 4 (Heat), Temp: 25C, Fan: 7 (Auto), "
"Swing(V): 15 (Auto), Swing(H): 13 (Auto), Quiet: Off, Powerful: Off, "
"Ion: On, Clock: 00:00, On Timer: 00:00, Off Timer: 00:00",
ac.toString());
}

0 comments on commit 5c931e0

Please sign in to comment.