From 684ae2e8db23b652c6b7b0ec9a02346ac2a115f6 Mon Sep 17 00:00:00 2001 From: Hans-Rune Bue Date: Thu, 12 Sep 2019 21:48:22 +0200 Subject: [PATCH] Support for MITSUBISHI KJ heatpumps (SG 161 0927 remote) Added support for MITSUBISHI KJ series heatpumps / remote control type SG161. Also added a IR_DEBUG_PACKET define to be able to feedback and debug the IR packet as added text output to a browser, curl or other http request tool. --- lib/HeatpumpIR/MitsubishiHeatpumpIR.cpp | 201 +++++++--- lib/HeatpumpIR/MitsubishiHeatpumpIR.h | 31 +- patches/MitsubishiKJ.patch | 495 ++++++++++++++++++++++++ src/_P088_HeatpumpIR.ino | 17 +- 4 files changed, 685 insertions(+), 59 deletions(-) create mode 100644 patches/MitsubishiKJ.patch diff --git a/lib/HeatpumpIR/MitsubishiHeatpumpIR.cpp b/lib/HeatpumpIR/MitsubishiHeatpumpIR.cpp index db9837f1b..096c12f32 100644 --- a/lib/HeatpumpIR/MitsubishiHeatpumpIR.cpp +++ b/lib/HeatpumpIR/MitsubishiHeatpumpIR.cpp @@ -1,5 +1,19 @@ #include +#ifdef USE_TIME_H +#include +#endif + +#ifdef IR_SEND_TIME +int sendHour = 16; +int sendMinute = 10; +int sendWeekday = 3; +#endif +#ifdef IR_DEBUG_PACKET +char IRPacket[180]; +#endif + + // These are protected methods, i.e. generic Mitsubishi instances cannot be created directly MitsubishiHeatpumpIR::MitsubishiHeatpumpIR() : HeatpumpIR() { @@ -52,6 +66,16 @@ MitsubishiFAHeatpumpIR::MitsubishiFAHeatpumpIR() : MitsubishiHeatpumpIR() _mitsubishiModel = MITSUBISHI_FA; } +MitsubishiKJHeatpumpIR::MitsubishiKJHeatpumpIR() : MitsubishiHeatpumpIR() +{ + static const char model[] PROGMEM = "mitsubishi_kj"; + static const char info[] PROGMEM = "{\"mdl\":\"mitsubishi_kj\",\"dn\":\"Mitsubishi KJ\",\"mT\":16,\"xT\":31,\"fs\":5,\"maint\":[10]}"; + + _model = model; + _info = info; + + _mitsubishiModel = MITSUBISHI_KJ; +} void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) { @@ -71,6 +95,7 @@ void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper if (_mitsubishiModel != MITSUBISHI_MSY) { + Serial.printf("Mode=%d\n",operatingModeCmd); switch (operatingModeCmd) { case MODE_AUTO: @@ -96,7 +121,7 @@ void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper } break; case MODE_MAINT: // Maintenance mode is just the heat mode at +10, FAN5 - if (_mitsubishiModel == MITSUBISHI_FE) { + if (_mitsubishiModel == MITSUBISHI_FE || _mitsubishiModel == MITSUBISHI_KJ) { operatingMode |= MITSUBISHI_AIRCON1_MODE_HEAT; temperature = 10; // Default to +10 degrees fanSpeedCmd = FAN_AUTO; @@ -159,59 +184,69 @@ void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper case FAN_4: fanSpeed = MITSUBISHI_AIRCON1_FAN4; break; + case FAN_5: + fanSpeed = MITSUBISHI_AIRCON1_FAN5; // Quiet mode on KJ + break; + } - if ( temperatureCmd > 16 && temperatureCmd < 32) + if ( temperature != 10 && temperatureCmd > 16 && temperatureCmd < 32) { temperature = temperatureCmd; } switch (swingVCmd) { - case VDIR_AUTO: - swingV = MITSUBISHI_AIRCON1_VS_AUTO; - break; - case VDIR_SWING: - swingV = MITSUBISHI_AIRCON1_VS_SWING; - break; - case VDIR_UP: - swingV = MITSUBISHI_AIRCON1_VS_UP; - break; - case VDIR_MUP: - swingV = MITSUBISHI_AIRCON1_VS_MUP; - break; - case VDIR_MIDDLE: - swingV = MITSUBISHI_AIRCON1_VS_MIDDLE; - break; - case VDIR_MDOWN: - swingV = MITSUBISHI_AIRCON1_VS_MDOWN; - break; - case VDIR_DOWN: - swingV = MITSUBISHI_AIRCON1_VS_DOWN; - break; + case VDIR_AUTO: + swingV = MITSUBISHI_AIRCON1_VS_AUTO; + break; + case VDIR_SWING: + swingV = MITSUBISHI_AIRCON1_VS_SWING; + break; + case VDIR_UP: + swingV = MITSUBISHI_AIRCON1_VS_UP; + break; + case VDIR_MUP: + swingV = MITSUBISHI_AIRCON1_VS_MUP; + break; + case VDIR_MIDDLE: + swingV = MITSUBISHI_AIRCON1_VS_MIDDLE; + break; + case VDIR_MDOWN: + swingV = MITSUBISHI_AIRCON1_VS_MDOWN; + break; + case VDIR_DOWN: + swingV = MITSUBISHI_AIRCON1_VS_DOWN; + break; } - switch (swingHCmd) - { - case HDIR_AUTO: - case HDIR_SWING: - swingH = MITSUBISHI_AIRCON1_HS_SWING; - break; - case HDIR_MIDDLE: - swingH = MITSUBISHI_AIRCON1_HS_MIDDLE; - break; - case HDIR_LEFT: - swingH = MITSUBISHI_AIRCON1_HS_LEFT; - break; - case HDIR_MLEFT: - swingH = MITSUBISHI_AIRCON1_HS_MLEFT; - break; - case HDIR_RIGHT: - swingH = MITSUBISHI_AIRCON1_HS_RIGHT; - break; - case HDIR_MRIGHT: - swingH = MITSUBISHI_AIRCON1_HS_MRIGHT; - break; + // KJ has no horizontal swing. Instead 0 means 2flow, else 1flow operation + if (_mitsubishiModel == MITSUBISHI_KJ) { + swingH = swingHCmd; // We pass the value unmodified + } + else { + switch (swingHCmd) + { + case HDIR_AUTO: + case HDIR_SWING: + swingH = MITSUBISHI_AIRCON1_HS_SWING; + break; + case HDIR_MIDDLE: + swingH = MITSUBISHI_AIRCON1_HS_MIDDLE; + break; + case HDIR_LEFT: + swingH = MITSUBISHI_AIRCON1_HS_LEFT; + break; + case HDIR_MLEFT: + swingH = MITSUBISHI_AIRCON1_HS_MLEFT; + break; + case HDIR_RIGHT: + swingH = MITSUBISHI_AIRCON1_HS_RIGHT; + break; + case HDIR_MRIGHT: + swingH = MITSUBISHI_AIRCON1_HS_MRIGHT; + break; + } } sendMitsubishi(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH); @@ -221,15 +256,41 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 { uint8_t MitsubishiTemplate[] = { 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x48, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00 }; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + uint8_t TempTranslate[] = { 0x82, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81 }; + // Sun Mon Tue Wed Thu Fri Sat uint8_t checksum = 0x00; +#ifdef USE_TIME_H + time_t now; + struct tm * timeinfo; +#endif + char pbyte[16]; + // MSY has a bit different template + if (_mitsubishiModel == MITSUBISHI_MSY) { + MitsubishiTemplate[14] = 0x00; + MitsubishiTemplate[15] = 0x00; + } + + // FA also has a bit different template + if (_mitsubishiModel == MITSUBISHI_FA) + { + MitsubishiTemplate[10] = 0x00; + MitsubishiTemplate[15] = 0x00; + } + + // KJ has a bit different template + if (_mitsubishiModel == MITSUBISHI_KJ) { + MitsubishiTemplate[15] = 0x00; + } + // Set the operatingmode on the template message MitsubishiTemplate[5] = powerMode; MitsubishiTemplate[6] = operatingMode; // Set the temperature on the template message if (temperature == 10) { + Serial.println(F("Temp=10 maintenance mode")); MitsubishiTemplate[7] = 0x00; // Maintenance mode MitsubishiTemplate[15] = 0x20; // This seems to be set to 0x20 on maintenance mode } else { @@ -242,23 +303,55 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 // Set the fan speed and vertical air direction on the template message MitsubishiTemplate[9] = fanSpeed | swingV; - // MSY has a bit different template - if (_mitsubishiModel == MITSUBISHI_MSY) { - MitsubishiTemplate[14] = 0x00; - MitsubishiTemplate[15] = 0x00; + + + if (_mitsubishiModel == MITSUBISHI_KJ) { + MitsubishiTemplate[8] = 0; + if ( operatingMode == MITSUBISHI_AIRCON1_MODE_AUTO || operatingMode == MITSUBISHI_AIRCON1_MODE_COOL ) + MitsubishiTemplate[8] = 0x6; + if ( operatingMode == MITSUBISHI_AIRCON1_MODE_DRY ) + MitsubishiTemplate[8] = 0x2; + + if ( swingH != 0 ) { + MitsubishiTemplate[16] = 0x02; + } } - // FA also has a bit different template - if (_mitsubishiModel == MITSUBISHI_FA) - { - MitsubishiTemplate[10] = 0x00; - MitsubishiTemplate[15] = 0x00; - } +#ifdef USE_TIME_H + time(&now); + timeinfo = localtime(&now); + + MitsubishiTemplate[10] = (uint8_t)(timeinfo->tm_hour * 60 + timeinfo->tm_min)/6; +#endif +#ifdef IR_SEND_TIME + if (_mitsubishiModel == MITSUBISHI_KJ) { + Serial.printf("Send time %02d:%02d day %d --> %x\n", sendHour, sendMinute, sendWeekday, (sendHour * 60 + sendMinute)/10); + MitsubishiTemplate[10] = (uint8_t)((sendHour * 60 + sendMinute)/10); + // Sunday is start if week , value 1 + MitsubishiTemplate[14] = TempTranslate[( sendWeekday - 1 ) % 7]; + } + else { + Serial.printf("Send time %02d:%02d --> %x\n", sendHour, sendMinute, (sendHour * 60 + sendMinute)/6); + MitsubishiTemplate[10] = (uint8_t)((sendHour * 60 + sendMinute)/6); + } +#endif + +#ifdef IR_DEBUG_PACKET + IRPacket[0] = (char) 0; + // Calculate the checksum + for (int i=0; i<17; i++) { + checksum += MitsubishiTemplate[i]; + sprintf_P(pbyte, PSTR("[%02d]=%02x "), i, (int) MitsubishiTemplate[i]); + strcat(IRPacket, pbyte); + } + Serial.println(IRPacket); +#else // Calculate the checksum for (int i=0; i<17; i++) { checksum += MitsubishiTemplate[i]; } +#endif MitsubishiTemplate[17] = checksum; diff --git a/lib/HeatpumpIR/MitsubishiHeatpumpIR.h b/lib/HeatpumpIR/MitsubishiHeatpumpIR.h index 9cce231ce..93a66bf78 100644 --- a/lib/HeatpumpIR/MitsubishiHeatpumpIR.h +++ b/lib/HeatpumpIR/MitsubishiHeatpumpIR.h @@ -4,6 +4,10 @@ #ifndef MitsubishiHeatpumpIR_h #define MitsubishiHeatpumpIR_h +// #define USE_TIME_H +#define IR_SEND_TIME +#define IR_DEBUG_PACKET + #include @@ -15,8 +19,8 @@ #define MITSUBISHI_AIRCON1_ZERO_SPACE 390 #define MITSUBISHI_AIRCON1_MSG_SPACE 17500 -// Mitsubishi mode codes -#define MITSUBISHI_AIRCON1_MODE_AUTO 0x20 +// Mitsubishi codes +#define MITSUBISHI_AIRCON1_MODE_AUTO 0x20 // Operating mode #define MITSUBISHI_AIRCON3_MODE_AUTO 0x60 // FA auto mode #define MITSUBISHI_AIRCON1_MODE_HEAT 0x08 #define MITSUBISHI_AIRCON3_MODE_HEAT 0x48 // FA heat mode @@ -31,7 +35,7 @@ #define MITSUBISHI_AIRCON1_MODE_ISEE 0x40 // Isee #define MITSUBISHI_AIRCON2_MODE_IFEEL 0x00 // MSY -#define MITSUBISHI_AIRCON1_MODE_OFF 0x00 // Power OFF +#define MITSUBISHI_AIRCON1_MODE_OFF 0x00 // Power FFi #define MITSUBISHI_AIRCON1_MODE_ON 0x20 // Power ON // Mitsubishi fan codes @@ -40,10 +44,15 @@ #define MITSUBISHI_AIRCON1_FAN2 0x02 #define MITSUBISHI_AIRCON1_FAN3 0x03 #define MITSUBISHI_AIRCON1_FAN4 0x04 +#define MITSUBISHI_AIRCON1_FAN5 0x05 // KJ +#define MITSUBISHI_AIRCON1_QUIET 0x05 // KJ // Mitsubishi vertical swing codes #define MITSUBISHI_AIRCON1_VS_SWING 0x78 #define MITSUBISHI_AIRCON1_VS_AUTO 0x40 +#define MITSUBISHI_AIRCON1_ECONOCOOL 0x20 // KJ byte 14 + 0x03 +#define MITSUBISHI_AIRCON1_ISAVE 0x20 // KJ byte 15 w temperature=0 +#define MITSUBISHI_AIRCON1_1FLOW 0x02 // KJ byte 16 #define MITSUBISHI_AIRCON1_VS_UP 0x48 #define MITSUBISHI_AIRCON1_VS_MUP 0x50 #define MITSUBISHI_AIRCON1_VS_MIDDLE 0x58 @@ -70,6 +79,7 @@ #define MITSUBISHI_FE 1 #define MITSUBISHI_MSY 2 #define MITSUBISHI_FA 3 +#define MITSUBISHI_KJ 4 class MitsubishiHeatpumpIR : public HeatpumpIR { @@ -108,4 +118,19 @@ class MitsubishiFAHeatpumpIR : public MitsubishiHeatpumpIR MitsubishiFAHeatpumpIR(); }; +class MitsubishiKJHeatpumpIR : public MitsubishiHeatpumpIR +{ + public: + MitsubishiKJHeatpumpIR(); +}; + +#ifdef IR_SEND_TIME +extern int sendHour; +extern int sendMinute; +extern int sendWeekday; +#endif +#ifdef IR_DEBUG_PACKET +extern char IRPacket[180]; +#endif + #endif diff --git a/patches/MitsubishiKJ.patch b/patches/MitsubishiKJ.patch new file mode 100644 index 000000000..343939843 --- /dev/null +++ b/patches/MitsubishiKJ.patch @@ -0,0 +1,495 @@ +*** a/_P088_HeatpumpIR.ino 2019-08-27 19:41:29.601146400 +0200 +--- b/_P088_HeatpumpIR.ino 2019-09-01 19:16:48.231090300 +0200 +*************** HeatpumpIR *heatpumpIR[] = {new Panasoni +*** 71,76 **** +--- 71,77 ---- + new CarrierNQVHeatpumpIR(), new CarrierMCAHeatpumpIR(), + new MideaHeatpumpIR(), new FujitsuHeatpumpIR(), + new MitsubishiFDHeatpumpIR(), new MitsubishiFEHeatpumpIR(), new MitsubishiMSYHeatpumpIR(), new MitsubishiFAHeatpumpIR(), ++ new MitsubishiKJHeatpumpIR(), + new SamsungAQVHeatpumpIR(), new SamsungFJMHeatpumpIR(),new SharpHeatpumpIR(), new DaikinHeatpumpIR(), + new MitsubishiHeavyZJHeatpumpIR(), new MitsubishiHeavyZMHeatpumpIR(), + new MitsubishiSEZKDXXHeatpumpIR(), +*************** boolean Plugin_088(byte function, struct +*** 202,208 **** + if (GetArgv(command, TmpStr1, 6)) temperature = str2int(TmpStr1.c_str()); + if (GetArgv(command, TmpStr1, 7)) vDir = str2int(TmpStr1.c_str()); + if (GetArgv(command, TmpStr1, 8)) hDir = str2int(TmpStr1.c_str()); +! + int i = 0; + do + { +--- 203,213 ---- + if (GetArgv(command, TmpStr1, 6)) temperature = str2int(TmpStr1.c_str()); + if (GetArgv(command, TmpStr1, 7)) vDir = str2int(TmpStr1.c_str()); + if (GetArgv(command, TmpStr1, 8)) hDir = str2int(TmpStr1.c_str()); +! #ifdef IR_SEND_TIME +! sendHour = hour(); +! sendMinute = minute(); +! sendWeekday = weekday(); +! #endif + int i = 0; + do + { +*************** boolean Plugin_088(byte function, struct +*** 220,228 **** +--- 225,241 ---- + irReceiver->enableIRIn(); // Start the receiver + #endif + addLog(LOG_LEVEL_INFO, F("P088: Heatpump IR code transmitted")); ++ #ifdef IR_DEBUG_PACKET ++ addLog(LOG_LEVEL_DEBUG, IRPacket); ++ #endif + if (printToWeb) + { + printWebString += F("P088: Heatpump IR code transmitted"); ++ #ifdef IR_DEBUG_PACKET ++ printWebString += F("
\n"); // do both
and \n to break line both in browser and curl -s ++ printWebString += IRPacket; ++ printWebString += F("\n"); ++ #endif + } + + // Panasonic CKP can only be turned ON/OFF by using the timer, +*************** boolean Plugin_088(byte function, struct +*** 288,291 **** + return success; + } + +! #endif // USES_P088 +\ No newline at end of file +--- 301,304 ---- + return success; + } + +! #endif // USES_P088 + +*** a/MitsubishiHeatpumpIR.cpp 2019-08-27 19:41:17.497615900 +0200 +--- b/MitsubishiHeatpumpIR.cpp 2019-09-01 19:16:35.373395300 +0200 +*************** +*** 1,5 **** +--- 1,19 ---- + #include + ++ #ifdef USE_TIME_H ++ #include ++ #endif ++ ++ #ifdef IR_SEND_TIME ++ int sendHour = 16; ++ int sendMinute = 10; ++ int sendWeekday = 3; ++ #endif ++ #ifdef IR_DEBUG_PACKET ++ char IRPacket[180]; ++ #endif ++ ++ + // These are protected methods, i.e. generic Mitsubishi instances cannot be created directly + MitsubishiHeatpumpIR::MitsubishiHeatpumpIR() : HeatpumpIR() + { +*************** MitsubishiFAHeatpumpIR::MitsubishiFAHeat +*** 52,57 **** +--- 66,81 ---- + _mitsubishiModel = MITSUBISHI_FA; + } + ++ MitsubishiKJHeatpumpIR::MitsubishiKJHeatpumpIR() : MitsubishiHeatpumpIR() ++ { ++ static const char model[] PROGMEM = "mitsubishi_kj"; ++ static const char info[] PROGMEM = "{\"mdl\":\"mitsubishi_kj\",\"dn\":\"Mitsubishi KJ\",\"mT\":16,\"xT\":31,\"fs\":5,\"maint\":[10]}"; ++ ++ _model = model; ++ _info = info; ++ ++ _mitsubishiModel = MITSUBISHI_KJ; ++ } + + void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) + { +*************** void MitsubishiHeatpumpIR::send(IRSender +*** 71,76 **** +--- 95,101 ---- + + if (_mitsubishiModel != MITSUBISHI_MSY) + { ++ Serial.printf("Mode=%d\n",operatingModeCmd); + switch (operatingModeCmd) + { + case MODE_AUTO: +*************** void MitsubishiHeatpumpIR::send(IRSender +*** 96,102 **** + } + break; + case MODE_MAINT: // Maintenance mode is just the heat mode at +10, FAN5 +! if (_mitsubishiModel == MITSUBISHI_FE) { + operatingMode |= MITSUBISHI_AIRCON1_MODE_HEAT; + temperature = 10; // Default to +10 degrees + fanSpeedCmd = FAN_AUTO; +--- 121,127 ---- + } + break; + case MODE_MAINT: // Maintenance mode is just the heat mode at +10, FAN5 +! if (_mitsubishiModel == MITSUBISHI_FE || _mitsubishiModel == MITSUBISHI_KJ) { + operatingMode |= MITSUBISHI_AIRCON1_MODE_HEAT; + temperature = 10; // Default to +10 degrees + fanSpeedCmd = FAN_AUTO; +*************** void MitsubishiHeatpumpIR::send(IRSender +*** 159,217 **** + case FAN_4: + fanSpeed = MITSUBISHI_AIRCON1_FAN4; + break; + } + +! if ( temperatureCmd > 16 && temperatureCmd < 32) + { + temperature = temperatureCmd; + } + + switch (swingVCmd) + { +! case VDIR_AUTO: +! swingV = MITSUBISHI_AIRCON1_VS_AUTO; +! break; +! case VDIR_SWING: +! swingV = MITSUBISHI_AIRCON1_VS_SWING; +! break; +! case VDIR_UP: +! swingV = MITSUBISHI_AIRCON1_VS_UP; +! break; +! case VDIR_MUP: +! swingV = MITSUBISHI_AIRCON1_VS_MUP; +! break; +! case VDIR_MIDDLE: +! swingV = MITSUBISHI_AIRCON1_VS_MIDDLE; +! break; +! case VDIR_MDOWN: +! swingV = MITSUBISHI_AIRCON1_VS_MDOWN; +! break; +! case VDIR_DOWN: +! swingV = MITSUBISHI_AIRCON1_VS_DOWN; +! break; +! } +! +! switch (swingHCmd) +! { +! case HDIR_AUTO: +! case HDIR_SWING: +! swingH = MITSUBISHI_AIRCON1_HS_SWING; + break; +! case HDIR_MIDDLE: +! swingH = MITSUBISHI_AIRCON1_HS_MIDDLE; + break; +! case HDIR_LEFT: +! swingH = MITSUBISHI_AIRCON1_HS_LEFT; + break; +! case HDIR_MLEFT: +! swingH = MITSUBISHI_AIRCON1_HS_MLEFT; + break; +! case HDIR_RIGHT: +! swingH = MITSUBISHI_AIRCON1_HS_RIGHT; + break; +! case HDIR_MRIGHT: +! swingH = MITSUBISHI_AIRCON1_HS_MRIGHT; + break; + } + + sendMitsubishi(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH); +--- 184,252 ---- + case FAN_4: + fanSpeed = MITSUBISHI_AIRCON1_FAN4; + break; ++ case FAN_5: ++ fanSpeed = MITSUBISHI_AIRCON1_FAN5; // Quiet mode on KJ ++ break; ++ + } + +! if ( temperature != 10 && temperatureCmd > 16 && temperatureCmd < 32) + { + temperature = temperatureCmd; + } + + switch (swingVCmd) + { +! case VDIR_AUTO: +! swingV = MITSUBISHI_AIRCON1_VS_AUTO; + break; +! case VDIR_SWING: +! swingV = MITSUBISHI_AIRCON1_VS_SWING; + break; +! case VDIR_UP: +! swingV = MITSUBISHI_AIRCON1_VS_UP; + break; +! case VDIR_MUP: +! swingV = MITSUBISHI_AIRCON1_VS_MUP; + break; +! case VDIR_MIDDLE: +! swingV = MITSUBISHI_AIRCON1_VS_MIDDLE; + break; +! case VDIR_MDOWN: +! swingV = MITSUBISHI_AIRCON1_VS_MDOWN; + break; ++ case VDIR_DOWN: ++ swingV = MITSUBISHI_AIRCON1_VS_DOWN; ++ break; ++ } ++ ++ // KJ has no horizontal swing. Instead 0 means 2flow, else 1flow operation ++ if (_mitsubishiModel == MITSUBISHI_KJ) { ++ swingH = swingHCmd; // We pass the value unmodified ++ } ++ else { ++ switch (swingHCmd) ++ { ++ case HDIR_AUTO: ++ case HDIR_SWING: ++ swingH = MITSUBISHI_AIRCON1_HS_SWING; ++ break; ++ case HDIR_MIDDLE: ++ swingH = MITSUBISHI_AIRCON1_HS_MIDDLE; ++ break; ++ case HDIR_LEFT: ++ swingH = MITSUBISHI_AIRCON1_HS_LEFT; ++ break; ++ case HDIR_MLEFT: ++ swingH = MITSUBISHI_AIRCON1_HS_MLEFT; ++ break; ++ case HDIR_RIGHT: ++ swingH = MITSUBISHI_AIRCON1_HS_RIGHT; ++ break; ++ case HDIR_MRIGHT: ++ swingH = MITSUBISHI_AIRCON1_HS_MRIGHT; ++ break; ++ } + } + + sendMitsubishi(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH); +*************** void MitsubishiHeatpumpIR::sendMitsubish +*** 221,235 **** +--- 256,296 ---- + { + uint8_t MitsubishiTemplate[] = { 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x48, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00 }; + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ++ uint8_t TempTranslate[] = { 0x82, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81 }; ++ // Sun Mon Tue Wed Thu Fri Sat + + uint8_t checksum = 0x00; ++ #ifdef USE_TIME_H ++ time_t now; ++ struct tm * timeinfo; ++ #endif ++ char pbyte[16]; ++ ++ // MSY has a bit different template ++ if (_mitsubishiModel == MITSUBISHI_MSY) { ++ MitsubishiTemplate[14] = 0x00; ++ MitsubishiTemplate[15] = 0x00; ++ } ++ ++ // FA also has a bit different template ++ if (_mitsubishiModel == MITSUBISHI_FA) ++ { ++ MitsubishiTemplate[10] = 0x00; ++ MitsubishiTemplate[15] = 0x00; ++ } + ++ // KJ has a bit different template ++ if (_mitsubishiModel == MITSUBISHI_KJ) { ++ MitsubishiTemplate[15] = 0x00; ++ } ++ + // Set the operatingmode on the template message + MitsubishiTemplate[5] = powerMode; + MitsubishiTemplate[6] = operatingMode; + + // Set the temperature on the template message + if (temperature == 10) { ++ Serial.println(F("Temp=10 maintenance mode")); + MitsubishiTemplate[7] = 0x00; // Maintenance mode + MitsubishiTemplate[15] = 0x20; // This seems to be set to 0x20 on maintenance mode + } else { +*************** void MitsubishiHeatpumpIR::sendMitsubish +*** 242,264 **** + // Set the fan speed and vertical air direction on the template message + MitsubishiTemplate[9] = fanSpeed | swingV; + +! // MSY has a bit different template +! if (_mitsubishiModel == MITSUBISHI_MSY) { +! MitsubishiTemplate[14] = 0x00; +! MitsubishiTemplate[15] = 0x00; + } + +! // FA also has a bit different template +! if (_mitsubishiModel == MITSUBISHI_FA) +! { +! MitsubishiTemplate[10] = 0x00; +! MitsubishiTemplate[15] = 0x00; + } + + // Calculate the checksum + for (int i=0; i<17; i++) { + checksum += MitsubishiTemplate[i]; + } + + MitsubishiTemplate[17] = checksum; + +--- 303,357 ---- + // Set the fan speed and vertical air direction on the template message + MitsubishiTemplate[9] = fanSpeed | swingV; + +! +! +! if (_mitsubishiModel == MITSUBISHI_KJ) { +! MitsubishiTemplate[8] = 0; +! if ( operatingMode == MITSUBISHI_AIRCON1_MODE_AUTO || operatingMode == MITSUBISHI_AIRCON1_MODE_COOL ) +! MitsubishiTemplate[8] = 0x6; +! if ( operatingMode == MITSUBISHI_AIRCON1_MODE_DRY ) +! MitsubishiTemplate[8] = 0x2; +! +! if ( swingH != 0 ) { +! MitsubishiTemplate[16] = 0x02; +! } + } + +! #ifdef USE_TIME_H +! time(&now); +! timeinfo = localtime(&now); +! +! MitsubishiTemplate[10] = (uint8_t)(timeinfo->tm_hour * 60 + timeinfo->tm_min)/6; +! #endif +! +! #ifdef IR_SEND_TIME +! if (_mitsubishiModel == MITSUBISHI_KJ) { +! Serial.printf("Send time %02d:%02d day %d --> %x\n", sendHour, sendMinute, sendWeekday, (sendHour * 60 + sendMinute)/10); +! MitsubishiTemplate[10] = (uint8_t)((sendHour * 60 + sendMinute)/10); +! // Sunday is start if week , value 1 +! MitsubishiTemplate[14] = TempTranslate[( sendWeekday - 1 ) % 7]; +! } +! else { +! Serial.printf("Send time %02d:%02d --> %x\n", sendHour, sendMinute, (sendHour * 60 + sendMinute)/6); +! MitsubishiTemplate[10] = (uint8_t)((sendHour * 60 + sendMinute)/6); + } ++ #endif + ++ #ifdef IR_DEBUG_PACKET ++ IRPacket[0] = (char) 0; ++ // Calculate the checksum ++ for (int i=0; i<17; i++) { ++ checksum += MitsubishiTemplate[i]; ++ sprintf_P(pbyte, PSTR("[%02d]=%02x "), i, (int) MitsubishiTemplate[i]); ++ strcat(IRPacket, pbyte); ++ } ++ Serial.println(IRPacket); ++ #else + // Calculate the checksum + for (int i=0; i<17; i++) { + checksum += MitsubishiTemplate[i]; + } ++ #endif + + MitsubishiTemplate[17] = checksum; + + +*** a/MitsubishiHeatpumpIR.h 2019-08-27 19:41:17.516596300 +0200 +--- b/MitsubishiHeatpumpIR.h 2019-09-01 19:16:35.378389700 +0200 +*************** +*** 4,9 **** +--- 4,13 ---- + #ifndef MitsubishiHeatpumpIR_h + #define MitsubishiHeatpumpIR_h + ++ // #define USE_TIME_H ++ #define IR_SEND_TIME ++ #define IR_DEBUG_PACKET ++ + #include + + +*************** +*** 15,22 **** + #define MITSUBISHI_AIRCON1_ZERO_SPACE 390 + #define MITSUBISHI_AIRCON1_MSG_SPACE 17500 + +! // Mitsubishi mode codes +! #define MITSUBISHI_AIRCON1_MODE_AUTO 0x20 + #define MITSUBISHI_AIRCON3_MODE_AUTO 0x60 // FA auto mode + #define MITSUBISHI_AIRCON1_MODE_HEAT 0x08 + #define MITSUBISHI_AIRCON3_MODE_HEAT 0x48 // FA heat mode +--- 19,26 ---- + #define MITSUBISHI_AIRCON1_ZERO_SPACE 390 + #define MITSUBISHI_AIRCON1_MSG_SPACE 17500 + +! // Mitsubishi codes +! #define MITSUBISHI_AIRCON1_MODE_AUTO 0x20 // Operating mode + #define MITSUBISHI_AIRCON3_MODE_AUTO 0x60 // FA auto mode + #define MITSUBISHI_AIRCON1_MODE_HEAT 0x08 + #define MITSUBISHI_AIRCON3_MODE_HEAT 0x48 // FA heat mode +*************** +*** 31,37 **** + #define MITSUBISHI_AIRCON1_MODE_ISEE 0x40 // Isee + #define MITSUBISHI_AIRCON2_MODE_IFEEL 0x00 // MSY + +! #define MITSUBISHI_AIRCON1_MODE_OFF 0x00 // Power OFF + #define MITSUBISHI_AIRCON1_MODE_ON 0x20 // Power ON + + // Mitsubishi fan codes +--- 35,41 ---- + #define MITSUBISHI_AIRCON1_MODE_ISEE 0x40 // Isee + #define MITSUBISHI_AIRCON2_MODE_IFEEL 0x00 // MSY + +! #define MITSUBISHI_AIRCON1_MODE_OFF 0x00 // Power FFi + #define MITSUBISHI_AIRCON1_MODE_ON 0x20 // Power ON + + // Mitsubishi fan codes +*************** +*** 40,49 **** +--- 44,58 ---- + #define MITSUBISHI_AIRCON1_FAN2 0x02 + #define MITSUBISHI_AIRCON1_FAN3 0x03 + #define MITSUBISHI_AIRCON1_FAN4 0x04 ++ #define MITSUBISHI_AIRCON1_FAN5 0x05 // KJ ++ #define MITSUBISHI_AIRCON1_QUIET 0x05 // KJ + + // Mitsubishi vertical swing codes + #define MITSUBISHI_AIRCON1_VS_SWING 0x78 + #define MITSUBISHI_AIRCON1_VS_AUTO 0x40 ++ #define MITSUBISHI_AIRCON1_ECONOCOOL 0x20 // KJ byte 14 + 0x03 ++ #define MITSUBISHI_AIRCON1_ISAVE 0x20 // KJ byte 15 w temperature=0 ++ #define MITSUBISHI_AIRCON1_1FLOW 0x02 // KJ byte 16 + #define MITSUBISHI_AIRCON1_VS_UP 0x48 + #define MITSUBISHI_AIRCON1_VS_MUP 0x50 + #define MITSUBISHI_AIRCON1_VS_MIDDLE 0x58 +*************** +*** 70,75 **** +--- 79,85 ---- + #define MITSUBISHI_FE 1 + #define MITSUBISHI_MSY 2 + #define MITSUBISHI_FA 3 ++ #define MITSUBISHI_KJ 4 + + class MitsubishiHeatpumpIR : public HeatpumpIR + { +*************** class MitsubishiFAHeatpumpIR : public Mi +*** 108,111 **** +--- 118,136 ---- + MitsubishiFAHeatpumpIR(); + }; + ++ class MitsubishiKJHeatpumpIR : public MitsubishiHeatpumpIR ++ { ++ public: ++ MitsubishiKJHeatpumpIR(); ++ }; ++ ++ #ifdef IR_SEND_TIME ++ extern int sendHour; ++ extern int sendMinute; ++ extern int sendWeekday; ++ #endif ++ #ifdef IR_DEBUG_PACKET ++ extern char IRPacket[180]; ++ #endif ++ + #endif + diff --git a/src/_P088_HeatpumpIR.ino b/src/_P088_HeatpumpIR.ino index a8de15c7a..862207b32 100644 --- a/src/_P088_HeatpumpIR.ino +++ b/src/_P088_HeatpumpIR.ino @@ -71,6 +71,7 @@ HeatpumpIR *heatpumpIR[] = {new PanasonicCKPHeatpumpIR(), new PanasonicDKEHeatpu new CarrierNQVHeatpumpIR(), new CarrierMCAHeatpumpIR(), new MideaHeatpumpIR(), new FujitsuHeatpumpIR(), new MitsubishiFDHeatpumpIR(), new MitsubishiFEHeatpumpIR(), new MitsubishiMSYHeatpumpIR(), new MitsubishiFAHeatpumpIR(), + new MitsubishiKJHeatpumpIR(), new SamsungAQVHeatpumpIR(), new SamsungFJMHeatpumpIR(),new SharpHeatpumpIR(), new DaikinHeatpumpIR(), new MitsubishiHeavyZJHeatpumpIR(), new MitsubishiHeavyZMHeatpumpIR(), new MitsubishiSEZKDXXHeatpumpIR(), @@ -202,7 +203,11 @@ boolean Plugin_088(byte function, struct EventStruct *event, String& string) if (GetArgv(command, TmpStr1, 6)) temperature = str2int(TmpStr1.c_str()); if (GetArgv(command, TmpStr1, 7)) vDir = str2int(TmpStr1.c_str()); if (GetArgv(command, TmpStr1, 8)) hDir = str2int(TmpStr1.c_str()); - +#ifdef IR_SEND_TIME + sendHour = hour(); + sendMinute = minute(); + sendWeekday = weekday(); +#endif int i = 0; do { @@ -220,9 +225,17 @@ boolean Plugin_088(byte function, struct EventStruct *event, String& string) irReceiver->enableIRIn(); // Start the receiver #endif addLog(LOG_LEVEL_INFO, F("P088: Heatpump IR code transmitted")); +#ifdef IR_DEBUG_PACKET + addLog(LOG_LEVEL_DEBUG, IRPacket); +#endif if (printToWeb) { printWebString += F("P088: Heatpump IR code transmitted"); +#ifdef IR_DEBUG_PACKET + printWebString += F("
\n"); // do both
and \n to break line both in browser and curl -s + printWebString += IRPacket; + printWebString += F("\n"); +#endif } // Panasonic CKP can only be turned ON/OFF by using the timer, @@ -288,4 +301,4 @@ boolean Plugin_088(byte function, struct EventStruct *event, String& string) return success; } -#endif // USES_P088 \ No newline at end of file +#endif // USES_P088