Skip to content

Commit

Permalink
DelonghiAc: Add basic send/decode support.
Browse files Browse the repository at this point in the history
* sendDelonghiAc() & decodeDelonhiAc()
* Unit tests for the above.
* Tests include real-world data

For #1096
  • Loading branch information
crankyoldgit committed May 1, 2020
1 parent 8e06cca commit 200ad4d
Show file tree
Hide file tree
Showing 13 changed files with 289 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "ir_Argo.h"
#include "ir_Coolix.h"
#include "ir_Daikin.h"
#include "ir_Delonghi.h"
#include "ir_Fujitsu.h"
#include "ir_Electra.h"
#include "ir_Goodweather.h"
Expand Down
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Airwell decode");
if (decodeAirwell(results, offset)) return true;
#endif // DECODE_AIRWELL
#if DECODE_DELONGHI_AC
DPRINTLN("Attempting Delonghi AC decode");
if (decodeDelonghiAc(results, offset)) return true;
#endif // DECODE_DELONGHI_AC
// 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 @@ -593,6 +593,11 @@ class IRrecv {
const uint16_t nbits = kAirwellBits,
const bool strict = true);
#endif // DECODE_AIRWELL
#if DECODE_DELONGHI_AC
bool decodeDelonghiAc(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kDelonghiAcBits,
const bool strict = true);
#endif // DECODE_DELONGHI_AC
};

#endif // IRRECV_H_
28 changes: 19 additions & 9 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,33 +573,40 @@
#endif // SEND_DAIKIN152

#ifndef DECODE_EPSON
#define DECODE_EPSON _IR_ENABLE_DEFAULT_
#define DECODE_EPSON _IR_ENABLE_DEFAULT_
#endif // DECODE_EPSON
#ifndef SEND_EPSON
#define SEND_EPSON _IR_ENABLE_DEFAULT_
#define SEND_EPSON _IR_ENABLE_DEFAULT_
#endif // SEND_EPSON

#ifndef DECODE_SYMPHONY
#define DECODE_SYMPHONY _IR_ENABLE_DEFAULT_
#define DECODE_SYMPHONY _IR_ENABLE_DEFAULT_
#endif // DECODE_SYMPHONY
#ifndef SEND_SYMPHONY
#define SEND_SYMPHONY _IR_ENABLE_DEFAULT_
#define SEND_SYMPHONY _IR_ENABLE_DEFAULT_
#endif // SEND_SYMPHONY

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

#ifndef DECODE_AIRWELL
#define DECODE_AIRWELL _IR_ENABLE_DEFAULT_
#define DECODE_AIRWELL _IR_ENABLE_DEFAULT_
#endif // DECODE_AIRWELL
#ifndef SEND_AIRWELL
#define SEND_AIRWELL _IR_ENABLE_DEFAULT_
#define SEND_AIRWELL _IR_ENABLE_DEFAULT_
#endif // SEND_AIRWELL

#ifndef DECODE_DELONGHI_AC
#define DECODE_DELONGHI_AC _IR_ENABLE_DEFAULT_
#endif // DECODE_DELONGHI_AC
#ifndef SEND_DELONGHI_AC
#define SEND_DELONGHI_AC _IR_ENABLE_DEFAULT_
#endif // SEND_DELONGHI_AC

#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 @@ -727,8 +734,9 @@ enum decode_type_t {
HITACHI_AC3,
DAIKIN64,
AIRWELL,
DELONGHI_AC, // 80
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = AIRWELL,
kLastDecodeType = DELONGHI_AC,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -775,6 +783,8 @@ const uint16_t kDaikin176DefaultRepeat = kNoRepeat;
const uint16_t kDaikin216StateLength = 27;
const uint16_t kDaikin216Bits = kDaikin216StateLength * 8;
const uint16_t kDaikin216DefaultRepeat = kNoRepeat;
const uint16_t kDelonghiAcBits = 64;
const uint16_t kDelonghiAcDefaultRepeat = kNoRepeat;
const uint16_t kDenonBits = 15;
const uint16_t kDenon48Bits = 48;
const uint16_t kDenonLegacyBits = 14;
Expand Down
6 changes: 6 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return 56;
case AMCOR:
case PIONEER:
case DELONGHI_AC:
return 64;
case ARGO:
return kArgoBits;
Expand Down Expand Up @@ -800,6 +801,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendDaikin64(data, nbits, min_repeat);
break;
#endif
#if SEND_DELONGHI_AC
case DELONGHI_AC:
sendDelonghiAc(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 @@ -573,6 +573,10 @@ class IRsend {
void sendAirwell(uint64_t data, uint16_t nbits = kAirwellBits,
uint16_t repeat = kAirwellMinRepeats);
#endif
#if SEND_DELONGHI_AC
void sendDelonghiAc(uint64_t data, uint16_t nbits = kDelonghiAcBits,
uint16_t repeat = kDelonghiAcDefaultRepeat);
#endif

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 @@ -247,4 +247,5 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_HITACHI_AC3 "\x0"
D_STR_DAIKIN64 "\x0"
D_STR_AIRWELL "\x0"
D_STR_DELONGHI_AC "\x0"
"\x0"; // This string requires double null termination.
90 changes: 90 additions & 0 deletions src/ir_Delonghi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2020 David Conran

#include "ir_Delonghi.h"
#include "IRrecv.h"
#include "IRsend.h"

// Delonghi based protocol.


const uint16_t kDelonghiAcHdrMark = 8984;
const uint16_t kDelonghiAcBitMark = 572;
const uint16_t kDelonghiAcHdrSpace = 4200;
const uint16_t kDelonghiAcOneSpace = 1558;
const uint16_t kDelonghiAcZeroSpace = 510;
const uint32_t kDelonghiAcGap = kDefaultMessageGap; // A totally made-up guess.
const uint16_t kDelonghiAcFreq = 38000; // Hz. (Guess: most common frequency.)
const uint16_t kDelonghiAcOverhead = 3;


#if SEND_DELONGHI_AC
// Send an Delonghi AC formatted message.
//
// Args:
// data: The message to be sent.
// nbits: The number of bits of the message to be sent.
// Typically kDelonghiAcBits.
// repeat: The number of times the command is to be repeated.
//
// Status: Alpha / Yet to be tested on a real device.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1096
void IRsend::sendDelonghiAc(const uint64_t data, const uint16_t nbits,
const uint16_t repeat) {
sendGeneric(kDelonghiAcHdrMark, kDelonghiAcHdrSpace,
kDelonghiAcBitMark, kDelonghiAcOneSpace,
kDelonghiAcBitMark, kDelonghiAcZeroSpace,
kDelonghiAcBitMark, kDelonghiAcGap,
data, nbits, kDelonghiAcFreq, false, // LSB First.
repeat, kDutyDefault);
}
#endif // SEND_DELONGHI_AC

#if DECODE_DELONGHI_AC
// Decode the supplied DELONGHI_AC message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// offset: The starting index to use when attempting to decode the raw data.
// Typically/Defaults to kStartOffset.
// nbits: The number of data bits to expect. Typically kDelonghiAcBits.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Appears to be working.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1096
bool IRrecv::decodeDelonghiAc(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (results->rawlen < 2 * nbits + kDelonghiAcOverhead - offset)
return false; // Too short a message to match.
if (strict && nbits != kDelonghiAcBits)
return false;

uint64_t data = 0;

// Header + Data + Footer
if (!matchGeneric(results->rawbuf + offset, &data,
results->rawlen - offset, nbits,
kDelonghiAcHdrMark, kDelonghiAcHdrSpace,
kDelonghiAcBitMark, kDelonghiAcOneSpace,
kDelonghiAcBitMark, kDelonghiAcZeroSpace,
kDelonghiAcBitMark, kDelonghiAcGap, true,
_tolerance, kMarkExcess, false)) return false;

// Compliance
// TODO(crankyoldgit): Enable this when written.
// if (strict && !IRDelonghiAc::validChecksum(data)) return false;

// Success
results->decode_type = decode_type_t::DELONGHI_AC;
results->bits = nbits;
results->value = data;
results->command = 0;
results->address = 0;
return true;
}
#endif // DECODE_DELONGHI_AC
72 changes: 72 additions & 0 deletions src/ir_Delonghi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Delonghi A/C
//
// Copyright 2020 David Conran

#ifndef IR_DELONGHI_H_
#define IR_DELONGHI_H_

#define __STDC_LIMIT_MACROS
#include <stdint.h>
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
#ifdef UNIT_TEST
#include "IRsend_test.h"
#endif

// Supports:
// Brand: Delonghi, Model: PAC A95

// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1096

// Kudos:
// TheMaxxz: For the breakdown and mapping of the bit values.

// Constants

// Classes
class IRDelonghiAc {
public:
explicit IRDelonghiAc(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);

void stateReset();
#if SEND_DELONGHI_AC
void send(const uint16_t repeat = kDelonghiAcDefaultRepeat);
int8_t calibrate(void) { return _irsend.calibrate(); }
#endif // SEND_DELONGHI_AC
void begin();
static uint8_t calcChecksum(const uint64_t state);
static bool validChecksum(const uint64_t state);
void setPower(const bool state);
bool getPower();
void on();
void off();
void setTemp(const uint8_t temp);
uint8_t getTemp();
void setFan(const uint8_t speed);
uint8_t getFan();
void setMode(const uint8_t mode);
uint8_t getMode();
uint64_t getRaw();
void setRaw(const uint64_t state);
uint8_t convertMode(const stdAc::opmode_t mode);
uint8_t convertFan(const stdAc::fanspeed_t speed);
static stdAc::opmode_t toCommonMode(const uint8_t mode);
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(void);
String toString();
#ifndef UNIT_TEST

private:
IRsend _irsend;
#else
IRsendTest _irsend;
#endif
uint64_t remote_state; // The state of the IR remote.
void checksum(void);
};
#endif // IR_DELONGHI_H_
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@
#endif // D_STR_DAIKIN216
#ifndef D_STR_DAIKIN64
#define D_STR_DAIKIN64 "DAIKIN64"
#ifndef D_STR_DELONGHI_AC
#define D_STR_DELONGHI_AC "DELONGHI_AC"
#endif // D_STR_DELONGHI_AC
#endif // D_STR_DAIKIN64
#ifndef D_STR_DENON
#define D_STR_DENON "DENON"
Expand Down
14 changes: 12 additions & 2 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TESTS = IRutils_test IRsend_test ir_NEC_test ir_GlobalCache_test \
ir_MWM_test ir_Vestel_test ir_Teco_test ir_Tcl_test ir_Lego_test IRac_test \
ir_MitsubishiHeavy_test ir_Trotec_test ir_Argo_test ir_Goodweather_test \
ir_Inax_test ir_Neoclima_test ir_Amcor_test ir_Epson_test ir_Symphony_test \
ir_Airwell_test
ir_Airwell_test ir_Delonghi_test

# All Google Test headers. Usually you shouldn't change this
# definition.
Expand Down Expand Up @@ -86,7 +86,7 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_Hitachi.o ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o \
ir_Pioneer.o ir_MWM.o ir_Vestel.o ir_Teco.o ir_Tcl.o ir_Lego.o ir_Argo.o \
ir_Trotec.o ir_MitsubishiHeavy.o ir_Goodweather.o ir_Inax.o ir_Neoclima.o \
ir_Amcor.o ir_Epson.o ir_Symphony.o ir_Airwell.o
ir_Amcor.o ir_Epson.o ir_Symphony.o ir_Airwell.o ir_Delonghi.o

# All the IR Protocol header files.
PROTOCOLS_H = $(USER_DIR)/ir_Amcor.h \
Expand All @@ -100,6 +100,7 @@ PROTOCOLS_H = $(USER_DIR)/ir_Amcor.h \
$(USER_DIR)/ir_Midea.h \
$(USER_DIR)/ir_Toshiba.h \
$(USER_DIR)/ir_Daikin.h \
$(USER_DIR)/ir_Delonghi.h \
$(USER_DIR)/ir_Goodweather.h \
$(USER_DIR)/ir_Kelvinator.h \
$(USER_DIR)/ir_Mitsubishi.h \
Expand Down Expand Up @@ -651,3 +652,12 @@ ir_Airwell_test.o : ir_Airwell_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)

ir_Airwell_test : $(COMMON_OBJ) ir_Airwell_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

ir_Delonghi.o : $(USER_DIR)/ir_Delonghi.h $(USER_DIR)/ir_Delonghi.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Delonghi.cpp

ir_Delonghi_test.o : ir_Delonghi_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Delonghi_test.cpp

ir_Delonghi_test : $(COMMON_OBJ) ir_Delonghi_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
Loading

0 comments on commit 200ad4d

Please sign in to comment.