From ebca04982e41fde11919c5a961a578fad4087b83 Mon Sep 17 00:00:00 2001 From: Toni Date: Tue, 3 Mar 2020 09:20:40 +0200 Subject: [PATCH 01/22] Mitsubishi MSY fixes --- MitsubishiHeatpumpIR.cpp | 96 ++++++++++++++++++++-------------------- MitsubishiHeatpumpIR.h | 3 +- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/MitsubishiHeatpumpIR.cpp b/MitsubishiHeatpumpIR.cpp index 096c12f..0925ad0 100644 --- a/MitsubishiHeatpumpIR.cpp +++ b/MitsubishiHeatpumpIR.cpp @@ -93,9 +93,48 @@ void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper powerMode = MITSUBISHI_AIRCON1_MODE_OFF; } - if (_mitsubishiModel != MITSUBISHI_MSY) + if (_mitsubishiModel == MITSUBISHI_FA) // set operating model for FA + { + switch (operatingModeCmd) + { + case MODE_AUTO: + operatingMode = MITSUBISHI_AIRCON3_MODE_AUTO; + break; + case MODE_HEAT: + operatingMode = MITSUBISHI_AIRCON3_MODE_HEAT; + break; + case MODE_COOL: + operatingMode = MITSUBISHI_AIRCON3_MODE_COOL; + break; + case MODE_DRY: + operatingMode = MITSUBISHI_AIRCON3_MODE_DRY; + break; + } + } + else if (_mitsubishiModel == MITSUBISHI_MSY) + { + operatingMode = MITSUBISHI_AIRCON2_MODE_COOL; + switch (operatingModeCmd) + { + case MODE_AUTO: + operatingMode = MITSUBISHI_AIRCON2_MODE_IFEEL; + break; + case MODE_HEAT: + operatingMode = MITSUBISHI_AIRCON1_MODE_HEAT; + break; + case MODE_COOL: + operatingMode = MITSUBISHI_AIRCON2_MODE_COOL; + break; + case MODE_DRY: + operatingMode = MITSUBISHI_AIRCON1_MODE_DRY; + break; + case MODE_FAN: + operatingMode = MITSUBISHI_AIRCON2_MODE_FAN; + break; + } + } + else { - Serial.printf("Mode=%d\n",operatingModeCmd); switch (operatingModeCmd) { case MODE_AUTO: @@ -129,43 +168,6 @@ void MitsubishiHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper break; } } - else if (_mitsubishiModel == MITSUBISHI_FA) // set operating model for FA - { - switch (operatingModeCmd) - { - case MODE_AUTO: - operatingMode = MITSUBISHI_AIRCON3_MODE_AUTO; - break; - case MODE_HEAT: - operatingMode = MITSUBISHI_AIRCON3_MODE_HEAT; - break; - case MODE_COOL: - operatingMode = MITSUBISHI_AIRCON3_MODE_COOL; - break; - case MODE_DRY: - operatingMode = MITSUBISHI_AIRCON3_MODE_DRY; - break; - } - } - else - { - operatingMode = MITSUBISHI_AIRCON2_MODE_COOL; - switch (operatingModeCmd) - { - case MODE_AUTO: - operatingMode = MITSUBISHI_AIRCON2_MODE_IFEEL; - break; - case MODE_COOL: - operatingMode = MITSUBISHI_AIRCON2_MODE_COOL; - break; - case MODE_DRY: - operatingMode = MITSUBISHI_AIRCON2_MODE_DRY; - break; - case MODE_FAN: - operatingMode = MITSUBISHI_AIRCON2_MODE_FAN; - break; - } - } switch (fanSpeedCmd) { @@ -282,8 +284,8 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 // 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; @@ -303,12 +305,12 @@ 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; - + if (_mitsubishiModel == MITSUBISHI_KJ) { MitsubishiTemplate[8] = 0; if ( operatingMode == MITSUBISHI_AIRCON1_MODE_AUTO || operatingMode == MITSUBISHI_AIRCON1_MODE_COOL ) - MitsubishiTemplate[8] = 0x6; + MitsubishiTemplate[8] = 0x6; if ( operatingMode == MITSUBISHI_AIRCON1_MODE_DRY ) MitsubishiTemplate[8] = 0x2; @@ -319,8 +321,8 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 #ifdef USE_TIME_H time(&now); - timeinfo = localtime(&now); - + timeinfo = localtime(&now); + MitsubishiTemplate[10] = (uint8_t)(timeinfo->tm_hour * 60 + timeinfo->tm_min)/6; #endif @@ -329,7 +331,7 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 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]; + MitsubishiTemplate[14] = TempTranslate[( sendWeekday - 1 ) % 7]; } else { Serial.printf("Send time %02d:%02d --> %x\n", sendHour, sendMinute, (sendHour * 60 + sendMinute)/6); @@ -385,5 +387,3 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 IR.mark(MITSUBISHI_AIRCON1_BIT_MARK); IR.space(0); } - - diff --git a/MitsubishiHeatpumpIR.h b/MitsubishiHeatpumpIR.h index 93a66bf..6dc0235 100644 --- a/MitsubishiHeatpumpIR.h +++ b/MitsubishiHeatpumpIR.h @@ -28,14 +28,13 @@ #define MITSUBISHI_AIRCON2_MODE_COOL 0x18 // MSY cool mode #define MITSUBISHI_AIRCON3_MODE_COOL 0x58 // FA cool mode #define MITSUBISHI_AIRCON1_MODE_DRY 0x10 -#define MITSUBISHI_AIRCON2_MODE_DRY 0x18 // MSY DRY mode #define MITSUBISHI_AIRCON3_MODE_DRY 0x50 // FA dry mode #define MITSUBISHI_AIRCON1_MODE_FAN 0x38 // EF 'FAN' mode #define MITSUBISHI_AIRCON2_MODE_FAN 0x38 // MSY fan mode #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_OFF 0x00 // Power OFF #define MITSUBISHI_AIRCON1_MODE_ON 0x20 // Power ON // Mitsubishi fan codes From bb914fe642d908a6810bcafae3896340e45ac846 Mon Sep 17 00:00:00 2001 From: Toni Date: Tue, 3 Mar 2020 09:21:10 +0200 Subject: [PATCH 02/22] Version 1.0.13 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index acb124b..87af6d5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HeatpumpIR -version=1.0.12 +version=1.0.13 author=Toni Arte maintainer=Toni Arte sentence=Heatpump / Air Conditioner infrared control From a731eef359befd16e21b481d61fb45628957d641 Mon Sep 17 00:00:00 2001 From: Toni Date: Wed, 25 Mar 2020 11:09:23 +0200 Subject: [PATCH 03/22] Serial.printf inside DEBUG flag, for Arduino Due compatibility --- MitsubishiHeatpumpIR.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MitsubishiHeatpumpIR.cpp b/MitsubishiHeatpumpIR.cpp index 0925ad0..cf5899e 100644 --- a/MitsubishiHeatpumpIR.cpp +++ b/MitsubishiHeatpumpIR.cpp @@ -328,13 +328,17 @@ void MitsubishiHeatpumpIR::sendMitsubishi(IRSender& IR, uint8_t powerMode, uint8 #ifdef IR_SEND_TIME if (_mitsubishiModel == MITSUBISHI_KJ) { +#ifdef DEBUG Serial.printf("Send time %02d:%02d day %d --> %x\n", sendHour, sendMinute, sendWeekday, (sendHour * 60 + sendMinute)/10); +#endif MitsubishiTemplate[10] = (uint8_t)((sendHour * 60 + sendMinute)/10); // Sunday is start if week , value 1 MitsubishiTemplate[14] = TempTranslate[( sendWeekday - 1 ) % 7]; } else { +#ifdef DEBUG Serial.printf("Send time %02d:%02d --> %x\n", sendHour, sendMinute, (sendHour * 60 + sendMinute)/6); +#endif MitsubishiTemplate[10] = (uint8_t)((sendHour * 60 + sendMinute)/6); } #endif From 304db4f7d6fbb1c9b2707ecc036f34c2ca2d0e19 Mon Sep 17 00:00:00 2001 From: Toni Date: Wed, 25 Mar 2020 11:09:54 +0200 Subject: [PATCH 04/22] Version 1.0.14 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 87af6d5..5035d76 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HeatpumpIR -version=1.0.13 +version=1.0.14 author=Toni Arte maintainer=Toni Arte sentence=Heatpump / Air Conditioner infrared control From 5a12bd2d0ef2d3fb474bfaf1dbae1b965e7250be Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 13 Apr 2020 10:16:02 +0300 Subject: [PATCH 05/22] #101 Ballu should implement the HeatpumpIR interface --- BalluHeatpumpIR.cpp | 13 ++++++------- BalluHeatpumpIR.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/BalluHeatpumpIR.cpp b/BalluHeatpumpIR.cpp index f7c5427..49288ab 100644 --- a/BalluHeatpumpIR.cpp +++ b/BalluHeatpumpIR.cpp @@ -10,16 +10,16 @@ BalluHeatpumpIR::BalluHeatpumpIR() } -void BalluHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd) +void BalluHeatpumpIR::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 = BALLU_AIRCON_MODE_COOL; uint8_t fanSpeed = BALLU_AIRCON_FAN_AUTO; uint8_t temperature = 21; uint8_t powerMode = 00; - - + + if (powerModeCmd == POWER_OFF) { powerMode = BALLU_AIRCON_MODE_OFF; @@ -43,7 +43,7 @@ void BalluHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operating break; } } - + switch (fanSpeedCmd) { case FAN_AUTO: @@ -59,12 +59,11 @@ void BalluHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operating fanSpeed = BALLU_AIRCON_FAN3; break; } - + if (temperatureCmd > 15 && temperatureCmd < 31) { temperature = temperatureCmd; } - sendBallu(IR, powerMode, operatingMode, fanSpeed, temperature); } diff --git a/BalluHeatpumpIR.h b/BalluHeatpumpIR.h index 2d65960..2982820 100644 --- a/BalluHeatpumpIR.h +++ b/BalluHeatpumpIR.h @@ -35,7 +35,7 @@ class BalluHeatpumpIR : public HeatpumpIR { public: BalluHeatpumpIR(); - void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); private: void sendBallu(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature); From 332b36ca5555165406dc1c7a5d384c311fe8a37d Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 13 Apr 2020 10:18:13 +0300 Subject: [PATCH 06/22] #102 DaikinHeatpumpARC480A14 should implement the HeatpumpIR interface. Add Daikin models into the HeatpumpIRFactory --- DaikinHeatpumpARC480A14IR.cpp | 6 ++++++ DaikinHeatpumpARC480A14IR.h | 1 + HeatpumpIRFactory.cpp | 6 ++++++ HeatpumpIRFactory.h | 2 ++ 4 files changed, 15 insertions(+) diff --git a/DaikinHeatpumpARC480A14IR.cpp b/DaikinHeatpumpARC480A14IR.cpp index 90f2db4..8dadffd 100644 --- a/DaikinHeatpumpARC480A14IR.cpp +++ b/DaikinHeatpumpARC480A14IR.cpp @@ -10,6 +10,12 @@ DaikinHeatpumpARC480A14IR::DaikinHeatpumpARC480A14IR() : HeatpumpIR() } +void DaikinHeatpumpARC480A14IR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) +{ + send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, + DAIKIN_AIRCON_COMFORT_OFF, DAIKIN_AIRCON_ECONO_OFF, DAIKIN_AIRCON_SENSOR_OFF, DAIKIN_AIRCON_QUIET_OFF, DAIKIN_AIRCON_POWERFUL_OFF); +} + // Daikin numeric values to command bytes void DaikinHeatpumpARC480A14IR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, uint8_t comfortModeCmd, uint8_t econoCmd, uint8_t sensorCmd, uint8_t quietCmd, uint8_t powerfulCmd) { diff --git a/DaikinHeatpumpARC480A14IR.h b/DaikinHeatpumpARC480A14IR.h index fb88d73..52ebba5 100644 --- a/DaikinHeatpumpARC480A14IR.h +++ b/DaikinHeatpumpARC480A14IR.h @@ -48,6 +48,7 @@ class DaikinHeatpumpARC480A14IR : public HeatpumpIR { public: DaikinHeatpumpARC480A14IR(); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, uint8_t comfortMode, uint8_t econo, uint8_t sensor, uint8_t quiet, uint8_t powerful); private: void sendDaikin(IRSender& IR, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH, uint8_t comfortMode, uint8_t econo, uint8_t sensor, uint8_t quiet, uint8_t powerful); diff --git a/HeatpumpIRFactory.cpp b/HeatpumpIRFactory.cpp index 9bcaea5..3fe0eb6 100644 --- a/HeatpumpIRFactory.cpp +++ b/HeatpumpIRFactory.cpp @@ -11,6 +11,12 @@ HeatpumpIR* HeatpumpIRFactory::create(const char *modelName) { return new CarrierMCAHeatpumpIR(); } else if (strcmp_P(modelName, PSTR("carrier_nqv")) == 0) { return new CarrierNQVHeatpumpIR(); + } else if (strcmp_P(modelName, PSTR("daikin_arc417")) == 0) { + return new DaikinHeatpumpARC417IR(); + } else if (strcmp_P(modelName, PSTR("daikin_arc480")) == 0) { + return new DaikinHeatpumpARC480A14IR(); + } else if (strcmp_P(modelName, PSTR("daikin")) == 0) { + return new DaikinHeatpumpIR(); } else if (strcmp_P(modelName, PSTR("fuego")) == 0) { return new FuegoHeatpumpIR(); } else if (strcmp_P(modelName, PSTR("fujitsu_awyz")) == 0) { diff --git a/HeatpumpIRFactory.h b/HeatpumpIRFactory.h index e22a2c6..dd03313 100644 --- a/HeatpumpIRFactory.h +++ b/HeatpumpIRFactory.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include From a5b9442061b1005c43d021f845a7975cabece067 Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 13 Apr 2020 10:22:36 +0300 Subject: [PATCH 07/22] Version 1.0.15 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 5035d76..3d21e07 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HeatpumpIR -version=1.0.14 +version=1.0.15 author=Toni Arte maintainer=Toni Arte sentence=Heatpump / Air Conditioner infrared control From a5c957a2470bb124f83a063a1b57f4e9e23479ab Mon Sep 17 00:00:00 2001 From: ericvb Date: Mon, 18 May 2020 20:15:27 +0200 Subject: [PATCH 08/22] Adding Samsung AQV12MSAN model --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 85726c0..49ebc15 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ An Arduino library to control pump/split unit air conditioner. Currently support * Panasonic E9/E12-JKE and E9/E12-NKE * Samsung * AQV12PSBN / AQV09ASA + * AQV12MSAN, Remote Control ARH-1362 * Samsung FJM (RJ040F2HXEA / 2XMH026FNEA), Remote Control P/N ARH-465 * Sharp AY-ZP40KR (remote control P/N CRMC-A788JBEZ), possibly also IVT * Toshiba Daiseikai (Toshiba remote control P/N WH-TA01EE). From afb87c4ccc6573d289ec12c76aee6a80458c7b02 Mon Sep 17 00:00:00 2001 From: ericvb Date: Mon, 18 May 2020 20:17:42 +0200 Subject: [PATCH 09/22] Adding supporting code for the Samsung AQV12MSAN model --- SamsungHeatpumpIR.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SamsungHeatpumpIR.h b/SamsungHeatpumpIR.h index 01a3128..fd43c9c 100644 --- a/SamsungHeatpumpIR.h +++ b/SamsungHeatpumpIR.h @@ -1,5 +1,6 @@ /* Samsung AQV12PSBN / AQV09ASA heatpump control (remote control P/N zzz) + Samsung AQV12MSAN (remote control ARH-1362) Samsung FJM (RJ040F2HXEA / MH026FNEA) heatpump control (remote control P/N ARH-465) */ #ifndef SamsungHeatpumpIR_h @@ -47,11 +48,13 @@ #define SAMSUNG_AIRCON2_VS_AUTO 0xF0 #define SAMSUNG_AIRCON2_TURBO 0x06 // 30 minutes of full power +#define MODEL_AQV12_MSAN 1 class SamsungHeatpumpIR : public HeatpumpIR { protected: SamsungHeatpumpIR(); + uint8_t _samsungAQVModel; public: virtual void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); @@ -82,4 +85,10 @@ class SamsungFJMHeatpumpIR : public SamsungHeatpumpIR void sendSamsung(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, bool turboMode); }; +class SamsungAQV12MSANHeatpumpIR : public SamsungAQVHeatpumpIR +{ + public: + SamsungAQV12MSANHeatpumpIR(); +}; + #endif From f7c9245a198ec678a7736e3452e730951ce6d820 Mon Sep 17 00:00:00 2001 From: ericvb Date: Mon, 18 May 2020 20:21:31 +0200 Subject: [PATCH 10/22] Adding supporting code for the Samsung AQV12MSAN model --- SamsungHeatpumpIR.cpp | 97 +++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/SamsungHeatpumpIR.cpp b/SamsungHeatpumpIR.cpp index 4ee8559..3992da5 100644 --- a/SamsungHeatpumpIR.cpp +++ b/SamsungHeatpumpIR.cpp @@ -20,6 +20,16 @@ SamsungAQVHeatpumpIR::SamsungAQVHeatpumpIR() : SamsungHeatpumpIR() _info = info; } +SamsungAQV12MSANHeatpumpIR::SamsungAQV12MSANHeatpumpIR() : SamsungAQVHeatpumpIR() +{ + static const char model[] PROGMEM = "samsung_aqv12msan"; + static const char info[] PROGMEM = "{\"mdl\":\"samsung_aqv12msan\",\"dn\":\"Samsung AQV12MSAN\",\"mT\":16,\"xT\":27,\"fs\":4}"; + + _model = model; + _info = info; + _samsungAQVModel = MODEL_AQV12_MSAN; +} + SamsungFJMHeatpumpIR::SamsungFJMHeatpumpIR() : SamsungHeatpumpIR() { static const char model[] PROGMEM = "samsung_fjm"; @@ -44,41 +54,29 @@ void SamsungAQVHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper uint8_t temperature = 23; uint8_t swingV = SAMSUNG_AIRCON1_VS_AUTO; - if (powerModeCmd == POWER_OFF) - { - powerMode = SAMSUNG_AIRCON1_MODE_OFF; - - if (operatingModeCmd == MODE_COOL) // Cooling-only models need to have COOL as the operating mode in power off - { - operatingMode = SAMSUNG_AIRCON1_MODE_COOL; - } - } - else - { - switch (operatingModeCmd) - { - case MODE_AUTO: - operatingMode = SAMSUNG_AIRCON1_MODE_AUTO; - fanSpeedCmd = FAN_AUTO; // Fan speed is always 'AUTO' in AUTO mode - break; - case MODE_HEAT: - operatingMode = SAMSUNG_AIRCON1_MODE_HEAT; - break; - case MODE_COOL: - operatingMode = SAMSUNG_AIRCON1_MODE_COOL; - break; - case MODE_DRY: - operatingMode = SAMSUNG_AIRCON1_MODE_DRY; - fanSpeedCmd = FAN_AUTO; // Fan speed is always 'AUTO' in DRY mode - break; - case MODE_FAN: - operatingMode = SAMSUNG_AIRCON1_MODE_FAN; - if ( fanSpeedCmd == FAN_AUTO ) { - fanSpeedCmd = FAN_1; // Fan speed cannot be 'AUTO' in FAN mode - } - break; - } - } + switch (operatingModeCmd) + { + case MODE_AUTO: + operatingMode = SAMSUNG_AIRCON1_MODE_AUTO; + fanSpeedCmd = FAN_AUTO; // Fan speed is always 'AUTO' in AUTO mode + break; + case MODE_HEAT: + operatingMode = SAMSUNG_AIRCON1_MODE_HEAT; + break; + case MODE_COOL: + operatingMode = SAMSUNG_AIRCON1_MODE_COOL; + break; + case MODE_DRY: + operatingMode = SAMSUNG_AIRCON1_MODE_DRY; + fanSpeedCmd = FAN_AUTO; // Fan speed is always 'AUTO' in DRY mode + break; + case MODE_FAN: + operatingMode = SAMSUNG_AIRCON1_MODE_FAN; + if ( fanSpeedCmd == FAN_AUTO ) { + fanSpeedCmd = FAN_1; // Fan speed cannot be 'AUTO' in FAN mode + } + break; + } switch (fanSpeedCmd) { @@ -108,6 +106,23 @@ void SamsungAQVHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t oper break; } + // power offmode is something special, so set it latest to treat + if (powerModeCmd == POWER_OFF) + { + powerMode = SAMSUNG_AIRCON1_MODE_OFF; + if (_samsungAQVModel == MODEL_AQV12_MSAN) + { + if (operatingModeCmd != MODE_AUTO) + { + swingV = 0xFF; + } + if (operatingModeCmd == MODE_AUTO) + { + fanSpeed = 0x0D; // reverse enginering remote + } + } + } + sendSamsung(IR, powerMode, operatingMode, fanSpeed, temperature, swingV); } @@ -157,7 +172,17 @@ void SamsungAQVHeatpumpIR::sendSamsung(IRSender& IR, uint8_t powerMode, uint8_t SamsungChecksum <<= 4; SamsungChecksum += 0x02; - SamsungTemplate[15] = SamsungChecksum; + // for some unknown reason the checksum is different when powering off for the model Samsung AQV12MSAN + if (_samsungAQVModel == MODEL_AQV12_MSAN + && powerMode == SAMSUNG_AIRCON1_MODE_OFF + && (operatingMode == SAMSUNG_AIRCON1_MODE_HEAT || operatingMode == SAMSUNG_AIRCON1_MODE_COOL)) + { + SamsungTemplate[15] = 0x02; // reverse enginering remote + } + else + { + SamsungTemplate[15] = SamsungChecksum; + } // 38 kHz PWM frequency IR.setFrequency(38); From 4ded006bd18116c01f7bd01b337bbcb6244a61d1 Mon Sep 17 00:00:00 2001 From: Lars Volker Date: Sun, 7 Jun 2020 10:59:34 -0700 Subject: [PATCH 11/22] Fix URL in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49ebc15..549189a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Original location: https://github.com/ToniA/arduino-heatpumpir For concrete examples, see the MySensors (Arduino + nRF24 radio) and ESPEasy (ESP8266 modules) integrations: * https://github.com/mysensors/MySensorsArduinoExamples/tree/master/examples/HeatpumpIRController -* https://github.com/ToniA/ESPEasy/blob/master/ESPEasy/_P115_HeatpumpIR.ino +* https://github.com/ToniA/ESPEasy/blob/HeatpumpIR/src/_P088_HeatpumpIR.ino An Arduino library to control pump/split unit air conditioner. Currently supporting at least these models: From 05e5a1d53112ebf7019d1ba7750e63e8fc0783ad Mon Sep 17 00:00:00 2001 From: Damir Konkov Date: Wed, 17 Jun 2020 12:57:45 +0300 Subject: [PATCH 12/22] Hyundai H-AR16-09H AC usage example as AUX ac. With MQTT Support. And home assistant sample climate config. --- README.md | 2 +- examples/AUXTest_MQTT/AUXTest_MQTT.ino | 127 ++++++++++++++++++ .../ESP8266-WeMos-D1-Mini-pinout-gpio-pin.png | Bin 0 -> 30366 bytes .../AUXTest_MQTT/home_assistant_climate.yaml | 10 ++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 examples/AUXTest_MQTT/AUXTest_MQTT.ino create mode 100644 examples/AUXTest_MQTT/ESP8266-WeMos-D1-Mini-pinout-gpio-pin.png create mode 100644 examples/AUXTest_MQTT/home_assistant_climate.yaml diff --git a/README.md b/README.md index 549189a..b7ea10d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ An Arduino library to control pump/split unit air conditioner. Currently support * Hisense AUD (remote control Y-H1-01, Y-H1-02(E), Y-J1, Y-E4-07) probably AUC model * Hyundai (remote control P/N Y512F2) * This is probably a generic Gree model - * Model H-AR21-07H (remote control P/N YKR-P/002E) confirmed as AUX + * Models H-AR21-07H / H-AR16-09H (remote control P/N YKR-P/002E) confirmed as AUX * Fujitsu Nocria AWYZ14 (remote control P/N AR-PZ2) * Also Fujitsu remote controls RY3-AR and AR-RCE1E * IVT AY-XP12FR-N (remote control CRMC-A673JBEZ) diff --git a/examples/AUXTest_MQTT/AUXTest_MQTT.ino b/examples/AUXTest_MQTT/AUXTest_MQTT.ino new file mode 100644 index 0000000..4ad88ce --- /dev/null +++ b/examples/AUXTest_MQTT/AUXTest_MQTT.ino @@ -0,0 +1,127 @@ +#include +#include +#include + +// This example based on DaikinTest_MQTT example. Thanks for @nick1802 for sample + +IRSenderESP8266 irSender(4); // Set GPIO pin number here. I use D2 pin on my Wemos D1 mini. See image in this example path +AUXHeatpumpIR *heatpumpIR; // This class also works with Hyundai H-AR16-09H model (rc YKR-P/002E) + +// TODO: Make next params manually configurable on first launch + +const char* ssid = "SSID";// your wifi name +const char* password = "SSIDPASS"; // your wifi password + +IPAddress ip(192, 168, 1, 100); //ESP static ip +IPAddress gateway(192, 168, 1, 1); //Set Gateway +IPAddress subnet(255, 255, 255, 0); //Subnet mask +const char* mqtt_server = "192.168.1.101"; // MQTT Server address +const int mqtt_port = 1883; // MQTT Server port (default: 1883) + +String client_id = "ESP-" + String(ESP.getChipId(), HEX); +String power_topic = "homeassistant/ac/" + client_id + "/switch"; +String mode_topic = "homeassistant/ac/" + client_id + "/mode/set"; +String fan_topic = "homeassistant/ac/" + client_id + "/fan_speed/set"; +String temperature_topic = "homeassistant/ac/" + client_id + "/temperature/set"; +String swing_topic = "homeassistant/ac/" + client_id + "/swing/set"; + +int power; +int acmode; +int fan; +int temp; +int swing; + +WiFiClient espClient; +PubSubClient client(espClient); + +void setup() { + Serial.begin(74880); + + setup_wifi(); + + heatpumpIR = new AUXHeatpumpIR(); // Initiate IR receiver object + + client.setServer(mqtt_server, mqtt_port); + client.setCallback(callback); // Set callback to MQTT client which calls everytime in main loop function + + Serial.println("Topics:"); + Serial.println(power_topic); + Serial.println(mode_topic); + Serial.println(fan_topic); + Serial.println(temperature_topic); + Serial.println(swing_topic); + + // Set default AC settings + power = POWER_OFF; + acmode = MODE_AUTO; + fan = FAN_AUTO; + temp = 25; + swing = VDIR_SWING; +} + +void setup_wifi() { + delay(10); + WiFi.mode(WIFI_STA); //set wifi to connect to your wifi and not start a AP + WiFi.config(ip, gateway, subnet); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { // waits for WIFI to connect + delay(500); + } + Serial.println(WiFi.localIP()); + Serial.print("RSSI : "); + Serial.println(WiFi.RSSI()); // wifi signal strength + Serial.println(); +} + +void reconnect() { + while (!client.connected()) { + client.loop(); + if (client.connect(client_id.c_str())) { + client.subscribe(power_topic.c_str()); + client.subscribe(mode_topic.c_str()); + client.subscribe(fan_topic.c_str()); + client.subscribe(temperature_topic.c_str()); + client.subscribe(swing_topic.c_str()); + } else { + delay(500); + } + } +} + +void callback(char* topic, byte* payload, unsigned int length) { + String Payload = ""; + for (int i = 0; i < length; i++) Payload += (char)payload[i]; + + if (String(topic) == power_topic) { + if (Payload == "ON") power = POWER_ON; + else if (Payload == "OFF") power = POWER_OFF; + } + if (String(topic) == mode_topic) { + if (Payload == "heat") acmode = MODE_HEAT; + else if (Payload == "cool") acmode = MODE_COOL; + else if (Payload == "dry") acmode = MODE_DRY; + else if (Payload == "fan_only") acmode = MODE_FAN; + else if (Payload == "auto") acmode = MODE_AUTO; + } + if (String(topic) == fan_topic) { + if (Payload == "auto") fan = FAN_AUTO; + else if (Payload == "low") fan = FAN_1; + else if (Payload == "medium") fan = FAN_2; + else if (Payload == "high") fan = FAN_3; + } + if (String(topic) == temperature_topic) { + temp = Payload.toInt(); + } + if (String(topic) == swing_topic) { + if (Payload == "on") swing = VDIR_AUTO; + else if (Payload == "off") swing = VDIR_SWING; + } + + heatpumpIR->send(irSender, power, acmode, fan, temp, swing, 0); // Last zero because my AC doesn't have horizontal swing function +} + +void loop() { + if (!client.connected()) reconnect(); + client.loop(); + delay(50); +} diff --git a/examples/AUXTest_MQTT/ESP8266-WeMos-D1-Mini-pinout-gpio-pin.png b/examples/AUXTest_MQTT/ESP8266-WeMos-D1-Mini-pinout-gpio-pin.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6fd8be8dbf213f8beba83a10ba0544ebf44c28 GIT binary patch literal 30366 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[IE5GT!pMQ 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 Date: Thu, 29 Oct 2020 21:57:03 +0100 Subject: [PATCH 13/22] Added ZH/LT-01 Remote to the "simple" example --- examples/simple/simple.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/simple/simple.ino b/examples/simple/simple.ino index ea62324..7210527 100644 --- a/examples/simple/simple.ino +++ b/examples/simple/simple.ino @@ -21,6 +21,7 @@ #include #include #include +#include #ifndef ESP8266 @@ -44,7 +45,7 @@ HeatpumpIR *heatpumpIR[] = {new PanasonicCKPHeatpumpIR(), new PanasonicDKEHeatpu new GreeGenericHeatpumpIR(), new GreeYANHeatpumpIR(), new GreeYAAHeatpumpIR(), new FuegoHeatpumpIR(), new ToshibaHeatpumpIR(), new ToshibaDaiseikaiHeatpumpIR(), new IVTHeatpumpIR(), new HitachiHeatpumpIR(), - new BalluHeatpumpIR(), new AUXHeatpumpIR(), + new BalluHeatpumpIR(), new AUXHeatpumpIR(), new ZHLT01HeatpumpIR(), NULL}; void setup() From a9579ca32c6016cc616715eb4d6551510b932814 Mon Sep 17 00:00:00 2001 From: Nateonas <40019341+Nateonas@users.noreply.github.com> Date: Thu, 29 Oct 2020 21:59:01 +0100 Subject: [PATCH 14/22] Added ZH/LT-01 Remote --- HeatpumpIRFactory.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HeatpumpIRFactory.cpp b/HeatpumpIRFactory.cpp index 3fe0eb6..2448fe7 100644 --- a/HeatpumpIRFactory.cpp +++ b/HeatpumpIRFactory.cpp @@ -77,7 +77,9 @@ HeatpumpIR* HeatpumpIRFactory::create(const char *modelName) { return new ToshibaDaiseikaiHeatpumpIR(); } else if (strcmp_P(modelName, PSTR("toshiba")) == 0) { return new ToshibaHeatpumpIR(); + } else if (strcmp_P(modelName, PSTR("ZHLT01")) == 0) { + return new ZHLT01HeatpumpIR(); } return NULL; -} \ No newline at end of file +} From f6c3f0767cb00710c0f513cf0ddb9470b3df6310 Mon Sep 17 00:00:00 2001 From: Nateonas <40019341+Nateonas@users.noreply.github.com> Date: Thu, 29 Oct 2020 22:00:15 +0100 Subject: [PATCH 15/22] Added ZH/LT-01 Remote --- HeatpumpIRFactory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HeatpumpIRFactory.h b/HeatpumpIRFactory.h index dd03313..cd6d206 100644 --- a/HeatpumpIRFactory.h +++ b/HeatpumpIRFactory.h @@ -26,7 +26,7 @@ #include #include #include - +#include class HeatpumpIRFactory { @@ -37,4 +37,4 @@ class HeatpumpIRFactory static HeatpumpIR* create(const char *modelName); }; -#endif \ No newline at end of file +#endif From 7f5ba0568419f7e93434743e79923c2ad4c8cc4c Mon Sep 17 00:00:00 2001 From: Nateonas <40019341+Nateonas@users.noreply.github.com> Date: Thu, 29 Oct 2020 22:01:53 +0100 Subject: [PATCH 16/22] Added support for ZH/LT-01 Remote controlled heatpumps --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 7a8a225..94e5831 100644 --- a/keywords.txt +++ b/keywords.txt @@ -38,6 +38,7 @@ IVTHeatpumpIR KEYWORD1 HitachiHeatpumpIR KEYWORD1 BalluHeatpumpIR KEYWORD1 AUXHeatpumpIR KEYWORD1 +ZHLT01HeatpumpIR KEYWORD1 IRSender KEYWORD1 IRSenderPWM KEYWORD1 From 709c5e1084180d880c030be91b2aa69bf7639a17 Mon Sep 17 00:00:00 2001 From: Nateonas <40019341+Nateonas@users.noreply.github.com> Date: Thu, 29 Oct 2020 22:04:48 +0100 Subject: [PATCH 17/22] Added support for ZH/LT-01 Remote controlled heatpumps --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b7ea10d..194a0cb 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,10 @@ An Arduino library to control pump/split unit air conditioner. Currently support * Tested with: RAS-10G2KVP-E RAS-10G2AVP-E and RAS-13G2KVP-E RAS-13G2AVP-E * Tosot T18H-SN/I (remote control P/N YAA1FB) as GreeYAA variant * Also marketed as Tadiran brand - +* ZH/LT-01 remote control + * Brands: Eurom, Chigo, Tristar, Tecnomaster, Elgin, Geant, Tekno, Topair, + Proma, Sumikura, JBS, Turbo Air, Nakatomy, Celestial Air, Ager, + Blueway, Airlux, etc. ## Instructions From e778a6bc68c0d784666be17ec90455eebf41e4ac Mon Sep 17 00:00:00 2001 From: Nateonas <40019341+Nateonas@users.noreply.github.com> Date: Thu, 29 Oct 2020 22:05:49 +0100 Subject: [PATCH 18/22] Added support for ZH/LT-01 Remote controlled heatpumps --- ZHLT01HeatpumpIR.h | 161 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 ZHLT01HeatpumpIR.h diff --git a/ZHLT01HeatpumpIR.h b/ZHLT01HeatpumpIR.h new file mode 100644 index 0000000..33e9623 --- /dev/null +++ b/ZHLT01HeatpumpIR.h @@ -0,0 +1,161 @@ +/******************************************************************************** + * Airconditional remote control encoder for: + * + * ZH/LT-01 Remote control https://www.google.com/search?q=zh/lt-01 + * + * The ZH/LT-01 remote control is used for many locally branded Split + * airconditioners, so it is better to name this protocol by the name of the + * REMOTE rather then the name of the Airconditioner. For this project I used + * a 2014 model Eurom-airconditioner, which is Dutch-branded and sold in + * the Netherlands at Hornbach. + * + * For airco-brands: + * Eurom + * Chigo + * Tristar + * Tecnomaster + * Elgin + * Geant + * Tekno + * Topair + * Proma + * Sumikura + * JBS + * Turbo Air + * Nakatomy + * Celestial Air + * Ager + * Blueway + * Airlux + * Etc. + * + *********************************************************************************** + * SUMMARY FUNCTIONAL DESCRIPTION + ********************************************************************************** + * The remote sends a 12 Byte message which contains all possible settings every + * time. + * + * Byte 11 (and 10) contain the remote control identifier and are always 0xD5 and + * 0x2A respectively for the ZH/LT-01 remote control. + * Every UNeven Byte (01,03,05,07 and 09) holds command data + * Every EVEN Byte (00,02,04,06,08 and 10) holds a checksum of the corresponding + * command-, or identifier-byte by _inverting_ the bits, for example: + * + * The identifier byte[11] = 0xD5 = B1101 0101 + * The checksum byte[10] = 0x2A = B0010 1010 + * + * So, you can check the message by: + * - inverting the bits of the checksum byte with the corresponding command-, or + * identifier byte, they should me the same, or + * - Summing up the checksum byte and the corresponding command-, or identifier byte, + * they should always add up to 0xFF = B11111111 = 255 + * + * Control bytes: + * [01] - Timer (1-24 hours, Off) + * Time is hardcoded to OFF + * + * [03] - LAMP ON/OFF, TURBO ON/OFF, HOLD ON/OFF + * Lamp and Hold are hardcoded to OFF + * Turbo is used for Cool and Heat is case of FAN_4 or FAN_5 + * + * [05] - Indicates which button the user _pressed_ on the remote control + * Hardcoded to POWER-button + * + * [07] - POWER ON/OFF, FAN AUTO/3/2/1, SLEEP ON/OFF, AIRFLOW ON/OFF, + * VERTICAL SWING/WIND/FIXED + * SLEEP is used for FAN_SILENT + * FAN_4 and FAN_5 are not supported, coded to FAN_3 or Turbo (byte [3]) + * Vertical Swing supports Fixed, Swing and "Wind" + * VDIR_AUTO = Wind + * VDIR_SWING = Swing + * All others = Fixed + * + * [09] - MODE AUTO/COOL/VENT/DRY/HEAT, TEMPERATURE (16 - 32°C) + * MODE_MAINT is not supported, but implemented as MODE_DRY at 30°C + * + * ****************************************************************************** + * Written by: Marcel van der Kooij + * Date: 2020-10-29 + * Version: 1.0 + *******************************************************************************/ + +#ifndef ZHLT01HeatpumpIR_h +#define ZHLT01HeatpumpIR_h + +#include + +/******************************************************************************** + * TIMINGS + * Space: Not used + * Header Mark: 6200 us + * Header Space: 7500 us + * Bit Mark: 475 us + * Zero Space: 525 us + * One Space: 1650 us + *******************************************************************************/ +#define AC1_HDR_MARK 6200 +#define AC1_HDR_SPACE 7500 +#define AC1_BIT_MARK 475 +#define AC1_ZERO_SPACE 525 +#define AC1_ONE_SPACE 1650 + +/******************************************************************************** + * + * ZHLT01 codes + * + *******************************************************************************/ + +// Power +#define AC1_POWER_OFF 0x00 +#define AC1_POWER_ON 0x02 + +// Operating Modes +#define AC1_MODE_AUTO 0x00 +#define AC1_MODE_COOL 0x20 +#define AC1_MODE_DRY 0x40 +#define AC1_MODE_FAN 0x60 +#define AC1_MODE_HEAT 0x80 +// MODE_MAINT is not supported, but implemented as DRY at 30°C. + +//Fan control +#define AC1_FAN_AUTO 0x00 +#define AC1_FAN_SILENT 0x01 +#define AC1_FAN1 0x60 +#define AC1_FAN2 0x40 +#define AC1_FAN3 0x20 +#define AC1_FAN_TURBO 0x08 +// FAN_4 and FAN_5 are not supported, but are implemented as button "TURBO" +// This only works for HEAT and COOL. Otherwise FAN_3 is used. + +// Vertical Swing +#define AC1_VDIR_WIND 0x00 // "Natural Wind", implemented on VDIR_AUTO +#define AC1_VDIR_SWING 0x04 // Swing +#define AC1_VDIR_FIXED 0x08 // All others are not supported + // and implemented as Fixed + +// Horizontal Swing +#define AC1_HDIR_SWING 0x00 // HDIR_SWING +#define AC1_HDIR_FIXED 0x10 // All others are not supported + // and implemented as Fixed + +class ZHLT01HeatpumpIR : public HeatpumpIR +{ + public: + ZHLT01HeatpumpIR(); + void send(IRSender& IR, uint8_t powerModeCmd, + uint8_t operatingModeCmd, + uint8_t fanSpeedCmd, + uint8_t temperatureCmd, + uint8_t swingVCmd, + uint8_t swingHCmd); + + protected: + void sendZHLT01(IRSender& IR, uint8_t powerMode, + uint8_t operatingMode, + uint8_t fanSpeed, + uint8_t temperature, + uint8_t swingV, + uint8_t swingH); +}; + +#endif From ced24b71638678fd7f16cfdb282e4ac35a430815 Mon Sep 17 00:00:00 2001 From: Nateonas <40019341+Nateonas@users.noreply.github.com> Date: Thu, 29 Oct 2020 22:06:34 +0100 Subject: [PATCH 19/22] Added support for ZH/LT-01 Remote controlled heatpumps --- ZHLT01HeatpumpIR.cpp | 198 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 ZHLT01HeatpumpIR.cpp diff --git a/ZHLT01HeatpumpIR.cpp b/ZHLT01HeatpumpIR.cpp new file mode 100644 index 0000000..3030183 --- /dev/null +++ b/ZHLT01HeatpumpIR.cpp @@ -0,0 +1,198 @@ +#include + +ZHLT01HeatpumpIR::ZHLT01HeatpumpIR() : HeatpumpIR() +{ + static const char model[] PROGMEM = "ZHLT01"; + static const char info[] PROGMEM = "{\"mdl\":\"ZHLT01\",\"dn\":\"ZHLT01\",\"mT\":18,\"xT\":32,\"fs\":3,\"maint\":[10]}}"; + + _model = model; + _info = info; +} + +void ZHLT01HeatpumpIR::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 powerMode = AC1_POWER_ON; + uint8_t operatingMode = AC1_MODE_AUTO; + uint8_t fanSpeed = AC1_FAN_AUTO; + uint8_t temperature = 25; + uint8_t swingV = AC1_VDIR_FIXED; + uint8_t swingH = AC1_HDIR_FIXED; + + if (powerModeCmd == 0) + { + powerMode = AC1_POWER_OFF; + } + + switch (operatingModeCmd) + { + case MODE_COOL: + operatingMode = AC1_MODE_COOL; + break; + case MODE_FAN: + operatingMode = AC1_MODE_FAN; + break; + case MODE_DRY: + operatingMode = AC1_MODE_DRY; + temperatureCmd = 25; + break; + case MODE_HEAT: + operatingMode = AC1_MODE_HEAT; + break; + case MODE_MAINT: + operatingMode = AC1_MODE_DRY; // MODE_MAINT not supported + temperatureCmd = 30; // Simlulated as DRY at 30°C + break; + default: + operatingMode = AC1_MODE_AUTO; + temperatureCmd = 25; // "Auto" = 25°C + } + + switch (fanSpeedCmd) + { + case FAN_AUTO: + fanSpeed = AC1_FAN_AUTO; + break; + case FAN_SILENT: + fanSpeed = AC1_FAN_SILENT; + break; + case FAN_1: + fanSpeed = AC1_FAN1; + break; + case FAN_2: + fanSpeed = AC1_FAN2; + break; + case FAN_3: + fanSpeed = AC1_FAN3; + break; + case FAN_4: + if ( operatingMode == AC1_MODE_COOL || operatingMode == AC1_MODE_HEAT ) + { fanSpeed = AC1_FAN_TURBO; } + else + { fanSpeed = AC1_FAN3; } + break; + case FAN_5: + if ( operatingMode == AC1_MODE_COOL || operatingMode == AC1_MODE_HEAT ) + { fanSpeed = AC1_FAN_TURBO; } + else + { fanSpeed = AC1_FAN3; } + break; + } + + switch (swingVCmd) + { + case VDIR_AUTO: + swingV = AC1_VDIR_WIND; + break; + case VDIR_SWING: + swingV = AC1_VDIR_SWING; + break; + default: + swingV = AC1_VDIR_FIXED; + } + + switch (swingHCmd) + { + case HDIR_SWING: + swingH = AC1_HDIR_SWING; + break; + default: + swingH = AC1_HDIR_FIXED; + } + +// temperature must be between 16 and 32 degrees + + temperature = temperatureCmd; + + if ( temperatureCmd < 16) + { + temperature = 16; + } + + if (temperatureCmd > 32) + { + temperature = 32; + } + + + sendZHLT01(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH); +} + +void ZHLT01HeatpumpIR::sendZHLT01(IRSender& IR, uint8_t powerMode, + uint8_t operatingMode, + uint8_t fanSpeed, + uint8_t temperature, + uint8_t swingV, + uint8_t swingH) +{ + uint8_t ZHLT01Template[] = { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x2A, 0xD5 }; + // Bytenumbers: 0 1 2 3 4 5 6 7 8 9 10 11 + +/******************************************************************************** + * Byte[03]: Button TURBO used for fanspeed 4 and 5 + * TURBO ON: Bxxxx1xxx (bit3) + * TURBO ON: Bxxxx0xxx + *******************************************************************************/ + if (fanSpeed == AC1_FAN_TURBO) + { + ZHLT01Template[3] = AC1_FAN_TURBO; + ZHLT01Template[2] = ~ ZHLT01Template[3]; + fanSpeed = AC1_FAN_AUTO; + } + + /******************************************************************************** + * Byte[07]: POWER, FAN, SLEEP, HORIZONTAL, VERTICAL + * POWER ON: B0xxxxx1x + * POWER OFF: B0xxxxx0x + * VERTICAL SWING: B0xxx01xx + * VERTICAL WIND: B0xxx00xx + * VERTICAL FIXED: B0xxx10xx + * HORIZONTAL SWING: B0xx0xxxx + * HORIZONTAL OFF: B0xx1xxxx + * FAN AUTO: B000xxxx0 + * FAN SILENT: B000xxxx1 + * FAN3: B001xxxx0 + * FAN2: B010xxxx0 + * FAN1: B011xxxx0 + *******************************************************************************/ + ZHLT01Template[7] = fanSpeed | powerMode | swingV | swingH; + ZHLT01Template[6] = ~ ZHLT01Template[7]; + +/******************************************************************************** + * Byte[09]: Mode, Temperature + * MODE AUTO: B000xxxxx + * MODE COOL: B001xxxxx + * MODE VENT: B011xxxxx + * MODE DRY: B010xxxxx + * MODE HEAT: B100xxxxx + * Temperature is determined by bit0-4: + * 0x00 = 16C + * 0x10 = 32C + *******************************************************************************/ + + ZHLT01Template[9] = operatingMode | (temperature - 16); + ZHLT01Template[8] = ~ ZHLT01Template[9]; + +// 38 kHz PWM frequency + IR.setFrequency(38); + +// Header + IR.mark(AC1_HDR_MARK); + IR.space(AC1_HDR_SPACE); + +// Data + for (unsigned int i=0; i Date: Wed, 18 Nov 2020 19:16:26 +1100 Subject: [PATCH 20/22] Added version and dependencies to library.json --- library.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library.json b/library.json index c9b892a..84aca8a 100644 --- a/library.json +++ b/library.json @@ -12,5 +12,14 @@ "url": "https://github.com/ToniA/arduino-heatpumpir.git" }, "frameworks": "arduino", - "platforms": "atmelavr" + "platforms": ["atmelavr", "espressif32", "espressif8266"], + "version": "1.0.15", + "dependencies": [ + { + "owner": "crankyoldgit", + "name": "IRremoteESP8266", + "version": "~2.7.12", + "platforms": ["espressif8266"] + } + ] } From 3fdd525fdc123790bcc3e5b858db6b78c3c7ae49 Mon Sep 17 00:00:00 2001 From: Clifford Roche Date: Tue, 9 Feb 2021 20:21:47 -0500 Subject: [PATCH 21/22] Add support for GreeYAC --- GreeHeatpumpIR.cpp | 85 +++++++++++++++++-- GreeHeatpumpIR.h | 45 +++++++--- examples/GreeTest/GreeYACTest/GreeYACTest.ino | 62 ++++++++++++++ 3 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 examples/GreeTest/GreeYACTest/GreeYACTest.ino diff --git a/GreeHeatpumpIR.cpp b/GreeHeatpumpIR.cpp index 8e691c9..8cd5292 100644 --- a/GreeHeatpumpIR.cpp +++ b/GreeHeatpumpIR.cpp @@ -36,12 +36,28 @@ GreeYAAHeatpumpIR::GreeYAAHeatpumpIR() : GreeHeatpumpIR() greeModel = GREE_YAA; } +// Support for YAC1FBF remote +GreeYACHeatpumpIR::GreeYACHeatpumpIR() : GreeHeatpumpIR() +{ + static const char model[] PROGMEM = "greeyac"; + static const char info[] PROGMEM = "{\"mdl\":\"greeyac\",\"dn\":\"Gree YAC\",\"mT\":16,\"xT\":30,\"fs\":3}"; + + _model = model; + _info = info; + greeModel = GREE_YAA; +} + void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) { send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, false); } void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode) +{ + send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, false, turboMode); +} + +void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode, bool iFeelMode) { (void)swingVCmd; (void)swingHCmd; @@ -55,6 +71,7 @@ void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingM uint8_t swingV = GREE_VDIR_AUTO; uint8_t swingH = GREE_HDIR_AUTO; + if (powerModeCmd == POWER_OFF) { powerMode = GREE_AIRCON1_POWER_OFF; @@ -100,7 +117,7 @@ void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingM } - if (greeModel == GREE_YAN) + if (greeModel == GREE_YAN || greeModel == GREE_YAC) { switch (swingVCmd) { @@ -152,6 +169,32 @@ void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingM swingV = GREE_VDIR_DOWN; break; } + + if (greeModel == GREE_YAC) + { + switch (swingHCmd) + { + case HDIR_AUTO: + case HDIR_SWING: + swingH = GREE_HDIR_SWING; + break; + case HDIR_LEFT: + swingH = GREE_HDIR_LEFT; + break; + case HDIR_MLEFT: + swingH = GREE_HDIR_MLEFT; + break; + case HDIR_MIDDLE: + swingH = GREE_HDIR_MIDDLE; + break; + case HDIR_MRIGHT: + swingH = GREE_HDIR_MRIGHT; + break; + case HDIR_RIGHT: + swingH = GREE_HDIR_RIGHT; + break; + } + } } @@ -160,11 +203,11 @@ void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingM temperature = temperatureCmd - 16; } - sendGree(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH, false); + sendGree(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH, turboMode, iFeelMode); } // Send the Gree code -void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH, bool turboMode) +void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH, bool turboMode, bool iFeelMode) { (void)swingH; @@ -179,7 +222,7 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating GreeTemplate[1] = temperature; // Gree YAN-specific - if (greeModel == GREE_YAN) + if (greeModel == GREE_YAN || greeModel == GREE_YAC) { GreeTemplate[2] = 0x60; GreeTemplate[2] = 0x50; @@ -191,6 +234,14 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating GreeTemplate[4] = swingV; } + if (greeModel == GREE_YAC) + { + GreeTemplate[4] |= (swingH << 4); + if (iFeelMode) + { + GreeTemplate[5] |= (1 << 3); + } + } if (greeModel == GREE_YAA) { // GreeTemplate[2] = 0xE0; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN @@ -213,7 +264,7 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating } // Calculate the checksum - if (greeModel == GREE_YAN) + if (greeModel == GREE_YAN || greeModel == GREE_YAC) { GreeTemplate[7] = ( (GreeTemplate[0] << 4) + @@ -261,6 +312,30 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating IR.sendIRbyte(GreeTemplate[i], GREE_AIRCON1_BIT_MARK, GREE_AIRCON1_ZERO_SPACE, GREE_AIRCON1_ONE_SPACE); } + // End mark + IR.mark(GREE_AIRCON1_BIT_MARK); + IR.space(0); +} + +// Sends current sensed temperatures, YAC remotes/supporting units only +void GreeYACHeatpumpIR::send(IRSender& IR, uint8_t currentTemperature) +{ + uint8_t GreeTemplate[] = { 0x00, 0x00 }; + + GreeTemplate[0] = currentTemperature; + GreeTemplate[1] = 0xA5; + + // 38 kHz PWM frequency + IR.setFrequency(38); + + // Send Header mark + IR.mark(GREE_AIRCON1_HDR_MARK); + IR.space(GREE_AIRCON1_HDR_SPACE); + + // send payload + IR.sendIRbyte(GreeTemplate[0], GREE_AIRCON1_BIT_MARK, GREE_AIRCON1_ZERO_SPACE, GREE_AIRCON1_ONE_SPACE); + IR.sendIRbyte(GreeTemplate[1], GREE_AIRCON1_BIT_MARK, GREE_AIRCON1_ZERO_SPACE, GREE_AIRCON1_ONE_SPACE); + // End mark IR.mark(GREE_AIRCON1_BIT_MARK); IR.space(0); diff --git a/GreeHeatpumpIR.h b/GreeHeatpumpIR.h index 525df90..ab19fd0 100644 --- a/GreeHeatpumpIR.h +++ b/GreeHeatpumpIR.h @@ -44,21 +44,22 @@ #define GREE_VDIR_MDOWN 0x05 #define GREE_VDIR_DOWN 0x06 -// Not available in this model. +// Only available on YAC // Horizontal air directions. Note that these cannot be set on all heat pumps -#define GREE_HDIR_AUTO 0 -#define GREE_HDIR_MANUAL 0 -#define GREE_HDIR_SWING 0 -#define GREE_HDIR_MIDDLE 0 -#define GREE_HDIR_LEFT 0 -#define GREE_HDIR_MLEFT 0 -#define GREE_HDIR_MRIGHT 0 -#define GREE_HDIR_RIGHT 0 +#define GREE_HDIR_AUTO 0x00 +#define GREE_HDIR_MANUAL 0x00 +#define GREE_HDIR_SWING 0x01 +#define GREE_HDIR_LEFT 0x02 +#define GREE_HDIR_MLEFT 0x03 +#define GREE_HDIR_MIDDLE 0x04 +#define GREE_HDIR_MRIGHT 0x05 +#define GREE_HDIR_RIGHT 0x06 // Gree model codes #define GREE_GENERIC 0 #define GREE_YAN 1 #define GREE_YAA 2 +#define GREE_YAC 3 class GreeHeatpumpIR : public HeatpumpIR @@ -70,9 +71,10 @@ class GreeHeatpumpIR : public HeatpumpIR public: void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd , uint8_t fanSpeedCmd , uint8_t temperatureCmd , uint8_t swingVCmd , uint8_t swingHCmd, bool turboMode); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd , uint8_t fanSpeedCmd , uint8_t temperatureCmd , uint8_t swingVCmd , uint8_t swingHCmd, bool turboMode, bool iFeelMode); private: - void sendGree(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH, bool turboMode); + void sendGree(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH, bool turboMode, bool iFeelMode); }; class GreeGenericHeatpumpIR : public GreeHeatpumpIR @@ -87,7 +89,10 @@ class GreeYANHeatpumpIR : public GreeHeatpumpIR GreeYANHeatpumpIR(); public: - void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode) + { + GreeHeatpumpIR::send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, turboMode); + } }; class GreeYAAHeatpumpIR : public GreeHeatpumpIR @@ -96,7 +101,23 @@ class GreeYAAHeatpumpIR : public GreeHeatpumpIR GreeYAAHeatpumpIR(); public: - void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode) + { + GreeHeatpumpIR::send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, turboMode); + } +}; + +class GreeYACHeatpumpIR : public GreeHeatpumpIR +{ + public: + GreeYACHeatpumpIR(); + + public: + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool turboMode, bool iFeelMode) + { + GreeHeatpumpIR::send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, turboMode, iFeelMode); + } + void send(IRSender& IR, uint8_t currentTemperature); }; #endif diff --git a/examples/GreeTest/GreeYACTest/GreeYACTest.ino b/examples/GreeTest/GreeYACTest/GreeYACTest.ino new file mode 100644 index 0000000..20606a3 --- /dev/null +++ b/examples/GreeTest/GreeYACTest/GreeYACTest.ino @@ -0,0 +1,62 @@ +#include +#include + +IRSenderPWM irSender(9); // IR led on Duemilanove digital pin 3, using Arduino PWM +//IRSenderBlaster irSender(3); // IR led on Duemilanove digital pin 3, using IR Blaster (generates the 38 kHz carrier) + +GreeYACHeatpumpIR *heatpumpIR; + +int redLED = 6; +int orangeLED = 5; +int greenLED = 4; +int blueLED = 3; + +void setup() +{ + Serial.begin(9600); + pinMode(redLED, OUTPUT); + pinMode(orangeLED, OUTPUT); + pinMode(greenLED, OUTPUT); + pinMode(blueLED, OUTPUT); + delay(500); + heatpumpIR = new GreeYACHeatpumpIR(); + Serial.println(F("Starting")); +} + +void loop() +{ + const char* buf; + + Serial.print(F("Sending IR to ")); + // Print the model + buf = heatpumpIR->model(); + // 'model' is a PROGMEM pointer, so need to write a byte at a time + while (char modelChar = pgm_read_byte(buf++)) + { + Serial.print(modelChar); + } + Serial.print(F(", info: ")); + // Print the info + buf = heatpumpIR->info(); + // 'info' is a PROGMEM pointer, so need to write a byte at a time + while (char infoChar = pgm_read_byte(buf++)) + { + Serial.print(infoChar); + } + Serial.println(); + + digitalWrite(orangeLED,HIGH); + delay(4000); + heatpumpIR->send(irSender, POWER_ON, MODE_HEAT, FAN_AUTO, 24, VDIR_AUTO, HDIR_AUTO, false, true); + + delay(4000); + heatpumpIR->send(irSender, 24); + + digitalWrite(orangeLED,LOW); + + digitalWrite(redLED, HIGH); + + // don't loop() + for(;;) + ; +} From 7d6c58e3f18a51dcc052234731723cbbddfad32d Mon Sep 17 00:00:00 2001 From: Clifford Roche Date: Sun, 14 Feb 2021 11:31:57 -0500 Subject: [PATCH 22/22] Fixing identifier for Gree YAC --- GreeHeatpumpIR.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GreeHeatpumpIR.cpp b/GreeHeatpumpIR.cpp index 8cd5292..dceb692 100644 --- a/GreeHeatpumpIR.cpp +++ b/GreeHeatpumpIR.cpp @@ -44,7 +44,7 @@ GreeYACHeatpumpIR::GreeYACHeatpumpIR() : GreeHeatpumpIR() _model = model; _info = info; - greeModel = GREE_YAA; + greeModel = GREE_YAC; } void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) @@ -117,7 +117,7 @@ void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingM } - if (greeModel == GREE_YAN || greeModel == GREE_YAC) + if (greeModel == GREE_YAN) { switch (swingVCmd) { @@ -143,7 +143,7 @@ void GreeHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingM } } - if (greeModel == GREE_YAA) + if (greeModel == GREE_YAA || greeModel == GREE_YAC) { switch (swingVCmd) { @@ -222,7 +222,7 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating GreeTemplate[1] = temperature; // Gree YAN-specific - if (greeModel == GREE_YAN || greeModel == GREE_YAC) + if (greeModel == GREE_YAN) { GreeTemplate[2] = 0x60; GreeTemplate[2] = 0x50; @@ -242,7 +242,7 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating GreeTemplate[5] |= (1 << 3); } } - if (greeModel == GREE_YAA) + if (greeModel == GREE_YAA || greeModel == GREE_YAC) { // GreeTemplate[2] = 0xE0; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN GreeTemplate[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN @@ -264,7 +264,7 @@ void GreeHeatpumpIR::sendGree(IRSender& IR, uint8_t powerMode, uint8_t operating } // Calculate the checksum - if (greeModel == GREE_YAN || greeModel == GREE_YAC) + if (greeModel == GREE_YAN) { GreeTemplate[7] = ( (GreeTemplate[0] << 4) +