diff --git a/DaikinHeatpumpIR.cpp b/DaikinHeatpumpIR.cpp new file mode 100644 index 0000000..af5d0bb --- /dev/null +++ b/DaikinHeatpumpIR.cpp @@ -0,0 +1,146 @@ +#include + +DaikinHeatpumpIR::DaikinHeatpumpIR() : HeatpumpIR() +{ + static const char PROGMEM model[] PROGMEM = "daikin"; + static const char PROGMEM info[] PROGMEM = "{\"mdl\":\"daikin\",\"dn\":\"Daikin\",\"mT\":18,\"xT\":30,\"fs\":6,\"maint\":[10,11,12,13,14,15,16,17]}}}"; + + _model = model; + _info = info; +} + + +// Daikin numeric values to command bytes +void DaikinHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) +{ + // Sensible defaults for the heat pump mode + + uint8_t operatingMode = DAIKIN_AIRCON_MODE_OFF | DAIKIN_AIRCON_MODE_AUTO; + uint8_t fanSpeed = DAIKIN_AIRCON_FAN_AUTO; + uint8_t temperature = 23; + + switch (powerModeCmd) + { + case POWER_ON: + operatingMode |= DAIKIN_AIRCON_MODE_ON; + break; + } + + switch (operatingModeCmd) + { + case MODE_AUTO: + operatingMode |= DAIKIN_AIRCON_MODE_AUTO; + break; + case MODE_HEAT: + operatingMode |= DAIKIN_AIRCON_MODE_HEAT; + break; + case MODE_COOL: + operatingMode |= DAIKIN_AIRCON_MODE_COOL; + break; + case MODE_DRY: + operatingMode |= DAIKIN_AIRCON_MODE_DRY; + temperatureCmd = 0x24; + break; + case MODE_FAN: + operatingMode |= DAIKIN_AIRCON_MODE_FAN; + temperatureCmd = 0xC0; + break; + } + + switch (fanSpeedCmd) + { + case FAN_AUTO: + fanSpeed = DAIKIN_AIRCON_FAN_AUTO; + break; + case FAN_1: + fanSpeed = DAIKIN_AIRCON_FAN1; + break; + case FAN_2: + fanSpeed = DAIKIN_AIRCON_FAN2; + break; + case FAN_3: + fanSpeed = DAIKIN_AIRCON_FAN3; + break; + case FAN_4: + fanSpeed = DAIKIN_AIRCON_FAN4; + break; + case FAN_5: + fanSpeed = DAIKIN_AIRCON_FAN5; + break; + } + + if ((operatingModeCmd == DAIKIN_AIRCON_MODE_HEAT && temperatureCmd >= 10 && temperatureCmd <= 30) || + (temperatureCmd >= 18 && temperatureCmd <= 30)) + { + temperature = temperatureCmd << 1; + } + + sendDaikin(IR, operatingMode, fanSpeed, temperature, swingVCmd, swingHCmd); +} + + +// Send the Daikin code +void DaikinHeatpumpIR::sendDaikin(IRSender& IR, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH) +{ + (void)swingV; + (void)swingH; + + uint8_t daikinTemplate[35] = { + 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7, // First header + // 0 1 2 3 4 5 6 7 + 0x11, 0xDA, 0x27, 0x00, 0x42, 0x49, 0x05, 0xA2, // Second header, this seems to have the wall clock time (bytes 12 & 13 are changing) + // 8 9 10 11 12 13 14 15 + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00 }; + // 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 + + daikinTemplate[21] = operatingMode; + daikinTemplate[22] = temperature; + daikinTemplate[24] = fanSpeed; + + // Checksum calculation + // * Checksums at bytes 7 and 15 are calculated the same way + uint8_t checksum = 0x00; + + for (int i=16; i<34; i++) { + checksum += daikinTemplate[i]; + } + + daikinTemplate[34] = checksum; + + // 38 kHz PWM frequency + IR.setFrequency(38); + + // Header + IR.mark(DAIKIN_AIRCON_HDR_MARK); + IR.space(DAIKIN_AIRCON_HDR_SPACE); + + // First header + for (int i=0; i<8; i++) { + IR.sendIRbyte(daikinTemplate[i], DAIKIN_AIRCON_BIT_MARK, DAIKIN_AIRCON_ZERO_SPACE, DAIKIN_AIRCON_ONE_SPACE); + } + + // Pause + new header + IR.mark(DAIKIN_AIRCON_BIT_MARK); + IR.space(DAIKIN_AIRCON_MSG_SPACE); + IR.mark(DAIKIN_AIRCON_HDR_MARK); + IR.space(DAIKIN_AIRCON_HDR_SPACE); + + // Second header - this probably has the wall clock time + for (int i=8; i<16; i++) { + IR.sendIRbyte(daikinTemplate[i], DAIKIN_AIRCON_BIT_MARK, DAIKIN_AIRCON_ZERO_SPACE, DAIKIN_AIRCON_ONE_SPACE); + } + + // Pause + new header + IR.mark(DAIKIN_AIRCON_BIT_MARK); + IR.space(DAIKIN_AIRCON_MSG_SPACE); + IR.mark(DAIKIN_AIRCON_HDR_MARK); + IR.space(DAIKIN_AIRCON_HDR_SPACE); + + // Last 19 bytes - the actual payload + for (int i=16; i<35; i++) { + IR.sendIRbyte(daikinTemplate[i], DAIKIN_AIRCON_BIT_MARK, DAIKIN_AIRCON_ZERO_SPACE, DAIKIN_AIRCON_ONE_SPACE); + } + + IR.mark(DAIKIN_AIRCON_BIT_MARK); + IR.space(0); +} \ No newline at end of file diff --git a/DaikinHeatpumpIR.h b/DaikinHeatpumpIR.h new file mode 100644 index 0000000..a0580d2 --- /dev/null +++ b/DaikinHeatpumpIR.h @@ -0,0 +1,44 @@ +/* + Daikin heatpump control (Daikin remote control P/N ARC433B50) +*/ +#ifndef DaikinHeatpumpIR_h +#define DaikinHeatpumpIR_h + +#include + + +// Daikin timing constants +#define DAIKIN_AIRCON_HDR_MARK 3360 // 3300 +#define DAIKIN_AIRCON_HDR_SPACE 1760 // 1600 +#define DAIKIN_AIRCON_BIT_MARK 360 // 310 +#define DAIKIN_AIRCON_ONE_SPACE 1370 // 1220 +#define DAIKIN_AIRCON_ZERO_SPACE 520 // 400 +#define DAIKIN_AIRCON_MSG_SPACE 32300 // 30800 + +// Daikin codes +#define DAIKIN_AIRCON_MODE_AUTO 0x00 // Operating mode +#define DAIKIN_AIRCON_MODE_HEAT 0x40 +#define DAIKIN_AIRCON_MODE_COOL 0x30 +#define DAIKIN_AIRCON_MODE_DRY 0x20 +#define DAIKIN_AIRCON_MODE_FAN 0x60 +#define DAIKIN_AIRCON_MODE_OFF 0x00 // Power OFF +#define DAIKIN_AIRCON_MODE_ON 0x01 +#define DAIKIN_AIRCON_FAN_AUTO 0xA0 // Fan speed +#define DAIKIN_AIRCON_FAN1 0x30 +#define DAIKIN_AIRCON_FAN2 0x40 +#define DAIKIN_AIRCON_FAN3 0x50 +#define DAIKIN_AIRCON_FAN4 0x60 +#define DAIKIN_AIRCON_FAN5 0x70 + + +class DaikinHeatpumpIR : public HeatpumpIR +{ + public: + DaikinHeatpumpIR(); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); + + private: + void sendDaikin(IRSender& IR, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH); +}; + +#endif \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index 7fa5eb1..a53afec 100644 --- a/keywords.txt +++ b/keywords.txt @@ -12,6 +12,7 @@ MitsubishiFDHeatpumpIR KEYWORD1 MitsubishiFEHeatpumpIR KEYWORD1 SamsungHeatpumpIR KEYWORD1 SharpHeatpumpIR KEYWORD1 +DaikinHeatpumpIR KEYWORD1 IRSender KEYWORD1