Skip to content

Commit

Permalink
Support for Daikin FFN-C A/C (#1065)
Browse files Browse the repository at this point in the history
* `sendDaikin64()`, `decodeDaikin64()`, & `IRDaikin64` class
* Add checksum support.
* Add Power Toggle, Mode, Temp, Fan speed, Swing, Turbo, Quiet, Sleep, Clock, On & Off timer control.
* Unit tests.
* Full support for common A/C api.
* Update support routines.

Fixes #1064
  • Loading branch information
crankyoldgit authored Mar 25, 2020
1 parent a31c6bd commit bdd0e64
Show file tree
Hide file tree
Showing 13 changed files with 936 additions and 3 deletions.
5 changes: 3 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: Tue Mar 17 13:45:51 2020 --->
Last generated: Wed Mar 25 11:38:37 2020 --->
# IR Protocols supported by this library

| Protocol | Brand | Model | A/C Model | Detailed A/C Support |
Expand All @@ -12,7 +12,7 @@
| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Beko](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | BINR 070/071 split-type A/C<BR>BINR 070/071 split-type A/C<BR>RG57K7(B)/BGEF Remote<BR>RG57K7(B)/BGEF Remote | | Yes |
| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | MS12FU-10HRDN1-QRD0GW(B) A/C<BR>MS12FU-10HRDN1-QRD0GW(B) A/C<BR>MSABAU-07HRFN1-QRD0GW A/C (circa 2016)<BR>MSABAU-07HRFN1-QRD0GW A/C (circa 2016)<BR>RG52D/BGE Remote<BR>RG52D/BGE Remote | | Yes |
| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Tokio](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | AATOEMF17-12CHR1SW split-type RG51\|50/BGE Remote<BR>AATOEMF17-12CHR1SW split-type RG51\|50/BGE Remote | | Yes |
| [Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | 17 Series A/C (DAIKIN128)<BR>ARC423A5 remote<BR>ARC433** remote<BR>ARC433B69 remote<BR>ARC477A1 remote<BR>ARC480A5 remote (DAIKIN152)<BR>BRC4C153 remote<BR>BRC52B63 remote (DAIKIN128)<BR>FTE12HV2S A/C<BR>FTXB09AXVJU A/C (DAIKIN128)<BR>FTXB12AXVJU A/C (DAIKIN128)<BR>FTXZ25NV1B A/C<BR>FTXZ35NV1B A/C<BR>FTXZ50NV1B A/C | | Yes |
| [Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | 17 Series A/C (DAIKIN128)<BR>ARC423A5 remote<BR>ARC433** remote<BR>ARC433B69 remote<BR>ARC477A1 remote<BR>ARC480A5 remote (DAIKIN152)<BR>BRC4C153 remote<BR>BRC52B63 remote (DAIKIN128)<BR>DGS01 remote (DAIKIN64)<BR>FFN-C/FCN-F Series A/C (DAIKIN64)<BR>FTE12HV2S A/C<BR>FTXB09AXVJU A/C (DAIKIN128)<BR>FTXB12AXVJU A/C (DAIKIN128)<BR>FTXZ25NV1B A/C<BR>FTXZ35NV1B A/C<BR>FTXZ50NV1B A/C | | Yes |
| [Denon](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Denon.cpp) | **Unknown** | | | - |
| [Dish](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Dish.cpp) | **DISH NETWORK** | echostar 301 | | - |
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C<BR>YKR-T/011 remote | | Yes |
Expand Down Expand Up @@ -94,6 +94,7 @@
- DAIKIN176
- DAIKIN2
- DAIKIN216
- DAIKIN64
- DENON
- DISH
- ELECTRA_AC
Expand Down
49 changes: 49 additions & 0 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
#if SEND_DAIKIN216
case decode_type_t::DAIKIN216:
#endif
#if SEND_DAIKIN64
case decode_type_t::DAIKIN64:
#endif
#if SEND_ELECTRA_AC
case decode_type_t::ELECTRA_AC:
#endif
Expand Down Expand Up @@ -461,6 +464,27 @@ void IRac::daikin216(IRDaikin216 *ac,
}
#endif // SEND_DAIKIN216

#if SEND_DAIKIN64
void IRac::daikin64(IRDaikin64 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const bool quiet, const bool turbo,
const int16_t sleep, const int16_t clock) {
ac->begin();
ac->setPowerToggle(on);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
ac->setFan(ac->convertFan(fan));
ac->setSwingVertical((int8_t)swingv >= 0);
ac->setTurbo(turbo);
ac->setQuiet(quiet);
ac->setSleep(sleep >= 0);
ac->setClock(clock);
ac->send();
}
#endif // SEND_DAIKIN64

#if SEND_ELECTRA_AC
void IRac::electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode,
Expand Down Expand Up @@ -1233,6 +1257,7 @@ stdAc::state_t IRac::handleToggles(const stdAc::state_t desired,
else
result.swingv = stdAc::swingv_t::kOff; // No change, so no toggle.
break;
case decode_type_t::DAIKIN64:
case decode_type_t::WHIRLPOOL_AC:
result.power = desired.power ^ prev->power;
break;
Expand Down Expand Up @@ -1390,6 +1415,15 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
break;
}
#endif // SEND_DAIKIN216
#if SEND_DAIKIN64
case DAIKIN64:
{
IRDaikin64 ac(_pin, _inverted, _modulation);
daikin64(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.quiet, send.turbo, send.sleep, send.clock);
break;
}
#endif // SEND_DAIKIN64
#if SEND_ELECTRA_AC
case ELECTRA_AC:
{
Expand Down Expand Up @@ -2008,6 +2042,13 @@ namespace IRAcUtils {
return ac.toString();
}
#endif // DECODE_DAIKIN216
#if DECODE_DAIKIN64
case decode_type_t::DAIKIN64: {
IRDaikin64 ac(kGpioUnused);
ac.setRaw(result->value); // Daikin64 uses value instead of state.
return ac.toString();
}
#endif // DECODE_DAIKIN216
#if DECODE_ELECTRA_AC
case decode_type_t::ELECTRA_AC: {
IRElectraAc ac(0);
Expand Down Expand Up @@ -2305,6 +2346,14 @@ namespace IRAcUtils {
break;
}
#endif // DECODE_DAIKIN216
#if DECODE_DAIKIN64
case decode_type_t::DAIKIN64: {
IRDaikin64 ac(kGpioUnused);
ac.setRaw(decode->value); // Uses value instead of state.
*result = ac.toCommon(prev);
break;
}
#endif // DECODE_DAIKIN64
#if DECODE_ELECTRA_AC
case decode_type_t::ELECTRA_AC: {
IRElectraAc ac(kGpioUnused);
Expand Down
8 changes: 8 additions & 0 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ void daikin216(IRDaikin216 *ac,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo);
#endif // SEND_DAIKIN216
#if SEND_DAIKIN64
void daikin64(IRDaikin64 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const bool quiet, const bool turbo,
const int16_t sleep = -1, const int16_t clock = -1);
#endif // SEND_DAIKIN64
#if SEND_ELECTRA_AC
void electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode,
Expand Down
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Symphony decode");
if (decodeSymphony(results, offset)) return true;
#endif // DECODE_SYMPHONY
#if DECODE_DAIKIN64
DPRINTLN("Attempting Daikin64 decode");
if (decodeDaikin64(results, offset)) return true;
#endif // DECODE_DAIKIN64
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
5 changes: 5 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,11 @@ class IRrecv {
const uint16_t nbits = kDaikinBits,
const bool strict = true);
#endif
#if DECODE_DAIKIN64
bool decodeDaikin64(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kDaikin64Bits,
const bool strict = true);
#endif // DECODE_DAIKIN64
#if DECODE_DAIKIN128
bool decodeDaikin128(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kDaikin128Bits,
Expand Down
12 changes: 11 additions & 1 deletion src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,13 @@
#define SEND_SYMPHONY _IR_ENABLE_DEFAULT_
#endif // SEND_SYMPHONY

#ifndef DECODE_DAIKIN64
#define DECODE_DAIKIN64 _IR_ENABLE_DEFAULT_
#endif // DECODE_DAIKIN64
#ifndef SEND_DAIKIN64
#define SEND_DAIKIN64 _IR_ENABLE_DEFAULT_
#endif // SEND_DAIKIN64

#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
Expand Down Expand Up @@ -711,8 +718,9 @@ enum decode_type_t {
EPSON, // 75
SYMPHONY,
HITACHI_AC3,
DAIKIN64,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = HITACHI_AC3,
kLastDecodeType = DAIKIN64,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -740,6 +748,8 @@ const uint16_t kDaikinDefaultRepeat = kNoRepeat;
const uint16_t kDaikin2StateLength = 39;
const uint16_t kDaikin2Bits = kDaikin2StateLength * 8;
const uint16_t kDaikin2DefaultRepeat = kNoRepeat;
const uint16_t kDaikin64Bits = 64;
const uint16_t kDaikin64DefaultRepeat = kNoRepeat;
const uint16_t kDaikin160StateLength = 20;
const uint16_t kDaikin160Bits = kDaikin160StateLength * 8;
const uint16_t kDaikin160DefaultRepeat = kNoRepeat;
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kDaikin2Bits;
case DAIKIN216:
return kDaikin216Bits;
case DAIKIN64:
return kDaikin64Bits;
case ELECTRA_AC:
return kElectraAcBits;
case GREE:
Expand Down Expand Up @@ -686,6 +688,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendCOOLIX(data, nbits, min_repeat);
break;
#endif
#if SEND_DAIKIN64
case DAIKIN64:
sendDaikin64(data, nbits, min_repeat);
break;
#endif
#if SEND_DENON
case DENON:
sendDenon(data, nbits, min_repeat);
Expand Down
4 changes: 4 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,10 @@ class IRsend {
const uint16_t nbytes = kDaikinStateLength,
const uint16_t repeat = kDaikinDefaultRepeat);
#endif
#if SEND_DAIKIN64
void sendDaikin64(const uint64_t data, const uint16_t nbits = kDaikin64Bits,
const uint16_t repeat = kDaikin64DefaultRepeat);
#endif // SEND_DAIKIN64
#if SEND_DAIKIN128
void sendDaikin128(const unsigned char data[],
const uint16_t nbytes = kDaikin128StateLength,
Expand Down
5 changes: 5 additions & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ decode_type_t strToDecodeType(const char * const str) {
return decode_type_t::DAIKIN2;
else if (!strcasecmp(str, "DAIKIN216"))
return decode_type_t::DAIKIN216;
else if (!strcasecmp(str, "DAIKIN64"))
return decode_type_t::DAIKIN64;
else if (!strcasecmp(str, "DENON"))
return decode_type_t::DENON;
else if (!strcasecmp(str, "DISH"))
Expand Down Expand Up @@ -307,6 +309,9 @@ String typeToString(const decode_type_t protocol, const bool isRepeat) {
case DAIKIN216:
result = F("DAIKIN216");
break;
case DAIKIN64:
result = F("DAIKIN64");
break;
case DENON:
result = F("DENON");
break;
Expand Down
Loading

0 comments on commit bdd0e64

Please sign in to comment.