Skip to content

Commit

Permalink
Add detailed support for Kelon ACs (#1494)
Browse files Browse the repository at this point in the history
* Detailed support for new Kelon A/C protocol.
* CommonAC api updated.
* Unit tests coverage added.
* Extensive user testing with actual device. Confirmed working.
* Add support for printing `int64_t`s.
* Allow converting signed ints to string.
* Add @depau to Contributors,
  • Loading branch information
depau authored Jul 3, 2021
1 parent 371b82e commit 7102d8f
Show file tree
Hide file tree
Showing 15 changed files with 1,235 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/Contributors.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [Mark Kuchel](https://github.com/kuchel77)
- [Christian Nilsson](https://github.com/NiKiZe)
- [Zhongxian Li](https://github.com/siriuslzx)
- [Davide Depau](https://github.com/Depau)

All contributors can be found on the [contributors site](https://github.com/crankyoldgit/IRremoteESP8266/graphs/contributors).

Expand Down
65 changes: 65 additions & 0 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "ir_Fujitsu.h"
#include "ir_Haier.h"
#include "ir_Hitachi.h"
#include "ir_Kelon.h"
#include "ir_Kelvinator.h"
#include "ir_LG.h"
#include "ir_Midea.h"
Expand Down Expand Up @@ -217,6 +218,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
#if SEND_HITACHI_AC424
case decode_type_t::HITACHI_AC424:
#endif
#if SEND_KELON
case decode_type_t::KELON:
#endif
#if SEND_KELVINATOR
case decode_type_t::KELVINATOR:
#endif
Expand Down Expand Up @@ -1250,6 +1254,37 @@ void IRac::hitachi424(IRHitachiAc424 *ac,
}
#endif // SEND_HITACHI_AC424

#if SEND_KELON
/// Send a Kelon A/C message with the supplied settings.
/// @param[in, out] ac A Ptr to an IRKelonAc object to use.
/// @param[in] togglePower Whether to toggle the unit's power
/// @param[in] mode The operation mode setting.
/// @param[in] dryGrade The dehumidification intensity grade
/// @param[in] degrees The temperature setting in degrees.
/// @param[in] fan The speed setting for the fan.
/// @param[in] toggleSwing Whether to toggle the swing setting
/// @param[in] superCool Run the device in Super cooling mode.
/// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on
void IRac::kelon(IRKelonAc *ac, const bool togglePower,
const stdAc::opmode_t mode, const int8_t dryGrade,
const float degrees, const stdAc::fanspeed_t fan,
const bool toggleSwing, const bool superCool,
const int16_t sleep) {
ac->begin();
ac->setMode(IRKelonAc::convertMode(mode));
ac->setFan(IRKelonAc::convertFan(fan));
ac->setTemp(static_cast<uint8_t>(degrees));
ac->setSleep(sleep >= 0);
ac->setSupercool(superCool);
ac->setDryGrade(dryGrade);

ac->setTogglePower(togglePower);
ac->setToggleSwingVertical(toggleSwing);

ac->send();
}
#endif // SEND_KELON

#if SEND_KELVINATOR
/// Send a Kelvinator A/C message with the supplied settings.
/// @param[in, out] ac A Ptr to an IRKelvinatorAC object to use.
Expand Down Expand Up @@ -2251,6 +2286,13 @@ 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::KELON:
if ((desired.swingv == stdAc::swingv_t::kOff) ^
(prev->swingv == stdAc::swingv_t::kOff)) // It changed, so toggle.
result.swingv = stdAc::swingv_t::kAuto;
else
result.swingv = stdAc::swingv_t::kOff; // No change, so no toggle.
// FALL-THRU
case decode_type_t::AIRWELL:
case decode_type_t::DAIKIN64:
case decode_type_t::PANASONIC_AC32:
Expand Down Expand Up @@ -2572,6 +2614,14 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
break;
}
#endif // SEND_HITACHI_AC424
#if SEND_KELON
case KELON: {
IRKelonAc ac(_pin, _inverted, _modulation);
kelon(&ac, send.power, send.mode, 0, send.degrees, send.fanspeed,
send.swingv != stdAc::swingv_t::kOff, send.turbo, send.sleep);
break;
}
#endif
#if SEND_KELVINATOR
case KELVINATOR:
{
Expand Down Expand Up @@ -3281,6 +3331,13 @@ namespace IRAcUtils {
return ac.toString();
}
#endif // DECODE_FUJITSU_AC
#if DECODE_KELON
case decode_type_t::KELON: {
IRKelonAc ac(kGpioUnused);
ac.setRaw(result->value);
return ac.toString();
}
#endif // DECODE_KELON
#if DECODE_KELVINATOR
case decode_type_t::KELVINATOR: {
IRKelvinatorAC ac(kGpioUnused);
Expand Down Expand Up @@ -3766,6 +3823,14 @@ namespace IRAcUtils {
break;
}
#endif // DECODE_HITACHI_AC424
#if DECODE_KELON
case decode_type_t::KELON: {
IRKelonAc ac(kGpioUnused);
ac.setRaw(decode->value);
*result = ac.toCommon();
break;
}
#endif // DECODE_KELON
#if DECODE_KELVINATOR
case decode_type_t::KELVINATOR: {
IRKelvinatorAC ac(kGpioUnused);
Expand Down
7 changes: 7 additions & 0 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "ir_Gree.h"
#include "ir_Haier.h"
#include "ir_Hitachi.h"
#include "ir_Kelon.h"
#include "ir_Kelvinator.h"
#include "ir_LG.h"
#include "ir_Midea.h"
Expand Down Expand Up @@ -289,6 +290,12 @@ void electra(IRElectraAc *ac,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv);
#endif // SEND_HITACHI_AC424
#if SEND_KELON
void kelon(IRKelonAc *ac, const bool togglePower, const stdAc::opmode_t mode,
const int8_t dryGrade, const float degrees,
const stdAc::fanspeed_t fan, const bool toggleSwing,
const bool superCool, const int16_t sleep);
#endif // SEND_KELON
#if SEND_KELVINATOR
void kelvinator(IRKelvinatorAC *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 @@ -1018,6 +1018,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Teknopoint decode");
if (decodeTeknopoint(results, offset)) return true;
#endif // DECODE_TEKNOPOINT
#if DECODE_KELON
DPRINTLN("Attempting Kelon decode");
if (decodeKelon(results, offset)) return true;
#endif // DECODE_KELON
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
4 changes: 4 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,10 @@ class IRrecv {
const uint16_t nbits = kTeknopointBits,
const bool strict = true);
#endif // DECODE_TEKNOPOINT
#if DECODE_KELON
bool decodeKelon(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kKelonBits, const bool strict = true);
#endif // DECODE_KELON
};

#endif // IRRECV_H_
14 changes: 12 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* Vestel AC code by Erdem U. Altınyurt
* Teco AC code by Fabien Valthier (hcoohb)
* Mitsubishi 112 AC Code by kuchel77
* Kelon AC code by Davide Depau (Depau)
*
* GPL license, all text above must be included in any redistribution
****************************************************/
Expand Down Expand Up @@ -761,6 +762,13 @@
#define SEND_TEKNOPOINT _IR_ENABLE_DEFAULT_
#endif // SEND_TEKNOPOINT

#ifndef DECODE_KELON
#define DECODE_KELON _IR_ENABLE_DEFAULT_
#endif // DECODE_KELON
#ifndef SEND_KELON
#define SEND_KELON _IR_ENABLE_DEFAULT_
#endif // SEND_KELON

#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 All @@ -774,7 +782,7 @@
DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3 || \
DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC || \
DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176 || \
DECODE_TEKNOPOINT || \
DECODE_TEKNOPOINT || DECODE_KELON || \
false)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
Expand Down Expand Up @@ -917,8 +925,9 @@ enum decode_type_t {
TRUMA, // 100
HAIER_AC176,
TEKNOPOINT,
KELON,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = TEKNOPOINT,
kLastDecodeType = KELON,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1031,6 +1040,7 @@ const uint16_t kHitachiAc424Bits = kHitachiAc424StateLength * 8;
const uint16_t kInaxBits = 24;
const uint16_t kInaxMinRepeat = kSingleRepeat;
const uint16_t kJvcBits = 16;
const uint16_t kKelonBits = 48;
const uint16_t kKelvinatorStateLength = 16;
const uint16_t kKelvinatorBits = kKelvinatorStateLength * 8;
const uint16_t kKelvinatorDefaultRepeat = kNoRepeat;
Expand Down
6 changes: 6 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
case SANYO_LC7461:
return kSanyoLC7461Bits; // 42
case GOODWEATHER:
case KELON:
case MIDEA:
case PANASONIC:
return 48;
Expand Down Expand Up @@ -869,6 +870,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendJVC(data, nbits, min_repeat);
break;
#endif
#if SEND_KELON
case KELON:
sendKelon(data, nbits, min_repeat);
break;
#endif // SEND_KELON
#if SEND_LASERTAG
case LASERTAG:
sendLasertag(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 @@ -717,6 +717,10 @@ class IRsend {
const uint16_t nbytes = kTeknopointStateLength,
const uint16_t repeat = kNoRepeat);
#endif // SEND_TEKNOPOINT
#if SEND_KELON
void sendKelon(const uint64_t data, const uint16_t nbits = kKelonBits,
const uint16_t repeat = kNoRepeat);
#endif // SEND_KELON

protected:
#ifdef UNIT_TEST
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,6 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_TRUMA "\x0"
D_STR_HAIER_AC176 "\x0"
D_STR_TEKNOPOINT "\x0"
D_STR_KELON "\x0"
///< New protocol strings should be added just above this line.
"\x0"; ///< This string requires double null termination.
25 changes: 25 additions & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ String uint64ToString(uint64_t input, uint8_t base) {
return result;
}

/// Convert a int64_t (signed long long) to a string.
/// Arduino String/toInt/Serial.print() can't handle printing 64 bit values.
/// @param[in] input The value to print
/// @param[in] base The output base.
/// @returns A String representation of the integer.
String int64ToString(int64_t input, uint8_t base) {
if (input < 0) {
return "-" + uint64ToString(-input, base);
}
return uint64ToString(input, base);
}

#ifdef ARDUINO
/// Print a uint64_t/unsigned long long to the Serial port
/// Serial.print() can't handle printing long longs. (uint64_t)
Expand Down Expand Up @@ -496,6 +508,19 @@ namespace irutils {
return addLabeledString(uint64ToString(value), label, precomma);
}

/// Create a String with a colon separated labeled Integer suitable for
/// Humans.
/// e.g. "Foo: 23"
/// @param[in] value The value to come after the label.
/// @param[in] label The label to precede the value.
/// @param[in] precomma Should the output string start with ", " or not?
/// @return The resulting String.
String addSignedIntToString(const int16_t value, const String label,
const bool precomma) {
return addLabeledString(int64ToString(value), label, precomma);
}


/// Generate the model string for a given Protocol/Model pair.
/// @param[in] protocol The IR protocol.
/// @param[in] model The model number for that protocol.
Expand Down
3 changes: 3 additions & 0 deletions src/IRutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const uint8_t kHighNibble = 4;
const uint8_t kModeBitsSize = 3;
uint64_t reverseBits(uint64_t input, uint16_t nbits);
String uint64ToString(uint64_t input, uint8_t base = 10);
String int64ToString(int64_t input, uint8_t base = 10);
String typeToString(const decode_type_t protocol,
const bool isRepeat = false);
void serialPrintUint64(uint64_t input, uint8_t base = 10);
Expand Down Expand Up @@ -49,6 +50,8 @@ namespace irutils {
const bool precomma = true);
String addIntToString(const uint16_t value, const String label,
const bool precomma = true);
String addSignedIntToString(const int16_t value, const String label,
const bool precomma = true);
String modelToStr(const decode_type_t protocol, const int16_t model);
String addModelToString(const decode_type_t protocol, const int16_t model,
const bool precomma = true);
Expand Down
Loading

0 comments on commit 7102d8f

Please sign in to comment.