From dbe983f4afbd9ac04d9860195eb0f3ea447b5cbd Mon Sep 17 00:00:00 2001 From: crankyoldgit Date: Mon, 7 Mar 2022 22:38:32 +1000 Subject: [PATCH 1/3] LG: Add Swing Toggle support for Model LG6711A20083V * Detect swingv toggle messages and set appropriate model. * Allow sending of swingv toggle messages. * Update supported models info * Various collateral updates. * Minor code cleanup. * Supporting unit tests. * Needs testing on a real device. Fixes #1770 --- src/IRac.cpp | 2 ++ src/IRsend.h | 1 + src/IRtext.cpp | 2 ++ src/IRtext.h | 16 +++++------ src/IRutils.cpp | 1 + src/ir_LG.cpp | 67 +++++++++++++++++++++++++++---------------- src/ir_LG.h | 10 +++++-- src/locale/defaults.h | 3 ++ test/ir_LG_test.cpp | 21 ++++++++++++++ 9 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/IRac.cpp b/src/IRac.cpp index a9f35ff5c..45c288fee 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -3458,6 +3458,8 @@ int16_t IRac::strToModel(const char *str, const int16_t def) { return lg_ac_remote_model_t::AKB74955603; } else if (!STRCASECMP(str, kAkb73757604Str)) { return lg_ac_remote_model_t::AKB73757604; + } else if (!STRCASECMP(str, kLg6711a20083vStr)) { + return lg_ac_remote_model_t::LG6711A20083V; // Panasonic A/C families } else if (!STRCASECMP(str, kLkeStr) || !STRCASECMP(str, kPanasonicLkeStr)) { diff --git a/src/IRsend.h b/src/IRsend.h index e51a214b0..271529f5d 100644 --- a/src/IRsend.h +++ b/src/IRsend.h @@ -196,6 +196,7 @@ enum lg_ac_remote_model_t { AKB75215403, // (2) LG2 28-bit Protocol AKB74955603, // (3) LG2 28-bit Protocol variant AKB73757604, // (4) LG2 Variant of AKB74955603 + LG6711A20083V, // (5) Same as GE6711AR2853M, but only SwingV toggle. }; diff --git a/src/IRtext.cpp b/src/IRtext.cpp index bd65ffd98..57d0c7c05 100644 --- a/src/IRtext.cpp +++ b/src/IRtext.cpp @@ -251,6 +251,8 @@ IRTEXT_CONST_STRING(kGe6711ar2853mStr, D_STR_GE6711AR2853M); ///< IRTEXT_CONST_STRING(kAkb75215403Str, D_STR_AKB75215403); ///< "AKB75215403" IRTEXT_CONST_STRING(kAkb74955603Str, D_STR_AKB74955603); ///< "AKB74955603" IRTEXT_CONST_STRING(kAkb73757604Str, D_STR_AKB73757604); ///< "AKB73757604" +IRTEXT_CONST_STRING(kLg6711a20083vStr, D_STR_LG6711A20083V); ///< + ///< "LG6711A20083V" IRTEXT_CONST_STRING(kKkg9ac1Str, D_STR_KKG9AC1); ///< "KKG9AC1" IRTEXT_CONST_STRING(kKkg29ac1Str, D_STR_KKG29AC1); ///< "KKG29AC1" IRTEXT_CONST_STRING(kLkeStr, D_STR_LKE); ///< "LKE" diff --git a/src/IRtext.h b/src/IRtext.h index 031f73879..aab671314 100644 --- a/src/IRtext.h +++ b/src/IRtext.h @@ -1,4 +1,4 @@ -// Copyright 2019-2021 - David Conran (@crankyoldgit) +// Copyright 2019-2022 - David Conran (@crankyoldgit) // This header file is to be included in files **other than** 'IRtext.cpp'. // // WARNING: Do not edit this file! This file is automatically generated by @@ -33,6 +33,7 @@ extern IRTEXT_CONST_PTR(k8CHeatStr); extern IRTEXT_CONST_PTR(kA705Str); extern IRTEXT_CONST_PTR(kA903Str); extern IRTEXT_CONST_PTR(kA907Str); +extern IRTEXT_CONST_PTR(kAbsenseDetectStr); extern IRTEXT_CONST_PTR(kAirFlowStr); extern IRTEXT_CONST_PTR(kAkb73757604Str); extern IRTEXT_CONST_PTR(kAkb74955603Str); @@ -74,6 +75,8 @@ extern IRTEXT_CONST_PTR(kDehumidifyStr); extern IRTEXT_CONST_PTR(kDg11j104Str); extern IRTEXT_CONST_PTR(kDg11j13aStr); extern IRTEXT_CONST_PTR(kDg11j191Str); +extern IRTEXT_CONST_PTR(kDirectIndirectModeStr); +extern IRTEXT_CONST_PTR(kDirectStr); extern IRTEXT_CONST_PTR(kDisplayTempStr); extern IRTEXT_CONST_PTR(kDkeStr); extern IRTEXT_CONST_PTR(kDownStr); @@ -108,8 +111,10 @@ extern IRTEXT_CONST_PTR(kHourStr); extern IRTEXT_CONST_PTR(kHumidStr); extern IRTEXT_CONST_PTR(kIdStr); extern IRTEXT_CONST_PTR(kIFeelStr); +extern IRTEXT_CONST_PTR(kIndirectStr); extern IRTEXT_CONST_PTR(kInsideStr); extern IRTEXT_CONST_PTR(kIonStr); +extern IRTEXT_CONST_PTR(kISeeStr); extern IRTEXT_CONST_PTR(kJkeStr); extern IRTEXT_CONST_PTR(kKkg29ac1Str); extern IRTEXT_CONST_PTR(kKkg9ac1Str); @@ -117,11 +122,12 @@ extern IRTEXT_CONST_PTR(kLastStr); extern IRTEXT_CONST_PTR(kLeftMaxNoSpaceStr); extern IRTEXT_CONST_PTR(kLeftMaxStr); extern IRTEXT_CONST_PTR(kLeftStr); +extern IRTEXT_CONST_PTR(kLg6711a20083vStr); extern IRTEXT_CONST_PTR(kLightStr); extern IRTEXT_CONST_PTR(kLightToggleStr); extern IRTEXT_CONST_PTR(kLkeStr); -extern IRTEXT_CONST_PTR(kLoStr); extern IRTEXT_CONST_PTR(kLockStr); +extern IRTEXT_CONST_PTR(kLoStr); extern IRTEXT_CONST_PTR(kLoudStr); extern IRTEXT_CONST_PTR(kLowerStr); extern IRTEXT_CONST_PTR(kLowestStr); @@ -231,11 +237,5 @@ extern IRTEXT_CONST_PTR(kYbofbStr); extern IRTEXT_CONST_PTR(kYesStr); extern IRTEXT_CONST_PTR(kZoneFollowStr); extern IRTEXT_CONST_PTR(kAllProtocolNamesStr); -extern IRTEXT_CONST_PTR(kISeeStr); -extern IRTEXT_CONST_PTR(kEcocoolStr); -extern IRTEXT_CONST_PTR(kAbsenseDetectStr); -extern IRTEXT_CONST_PTR(kDirectIndirectModeStr); -extern IRTEXT_CONST_PTR(kDirectStr); -extern IRTEXT_CONST_PTR(kIndirectStr); #endif // IRTEXT_H_ diff --git a/src/IRutils.cpp b/src/IRutils.cpp index 166813035..0547a0fce 100644 --- a/src/IRutils.cpp +++ b/src/IRutils.cpp @@ -636,6 +636,7 @@ namespace irutils { case lg_ac_remote_model_t::AKB75215403: return kAkb75215403Str; case lg_ac_remote_model_t::AKB74955603: return kAkb74955603Str; case lg_ac_remote_model_t::AKB73757604: return kAkb73757604Str; + case lg_ac_remote_model_t::LG6711A20083V: return kLg6711a20083vStr; default: return kUnknownStr; } break; diff --git a/src/ir_LG.cpp b/src/ir_LG.cpp index 9b3664bc6..94cf01cd6 100644 --- a/src/ir_LG.cpp +++ b/src/ir_LG.cpp @@ -22,6 +22,7 @@ using irutils::addModeToString; using irutils::addModelToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::addToggleToString; using irutils::addSwingVToString; using irutils::addIntToString; @@ -255,6 +256,11 @@ void IRLgAc::send(const uint16_t repeat) { _irsend.send(_protocol, getRaw(), kLgBits, repeat); // Some models have extra/special settings & controls switch (getModel()) { + case lg_ac_remote_model_t::LG6711A20083V: + // Only send the swing setting if we need to. + if (_swingv != _swingv_prev) + _irsend.send(_protocol, _swingv, kLgBits, repeat); + break; case lg_ac_remote_model_t::AKB74955603: // Only send the swing setting if we need to. if (_swingv != _swingv_prev) @@ -309,6 +315,7 @@ void IRLgAc::setModel(const lg_ac_remote_model_t model) { _protocol = decode_type_t::LG2; break; case lg_ac_remote_model_t::GE6711AR2853M: + case lg_ac_remote_model_t::LG6711A20083V: _protocol = decode_type_t::LG; break; default: @@ -319,24 +326,25 @@ void IRLgAc::setModel(const lg_ac_remote_model_t model) { /// Get the model of the A/C. /// @return The enum of the compatible model. -lg_ac_remote_model_t IRLgAc::getModel(void) const { - return _model; -} +lg_ac_remote_model_t IRLgAc::getModel(void) const { return _model; } /// Check if the stored code must belong to a AKB74955603 model. /// @return true, if it is AKB74955603 message. Otherwise, false. /// @note Internal use only. bool IRLgAc::_isAKB74955603(void) const { return ((_.raw & kLgAcAKB74955603DetectionMask) && _isNormal()) || - isSwingV() || isLightToggle(); + (isSwingV() && !isSwingVToggle()) || isLightToggle(); } /// Check if the stored code must belong to a AKB73757604 model. /// @return true, if it is AKB73757604 message. Otherwise, false. /// @note Internal use only. -bool IRLgAc::_isAKB73757604(void) const { - return isSwingH() || isVaneSwingV(); -} +bool IRLgAc::_isAKB73757604(void) const { return isSwingH() || isVaneSwingV(); } + +/// Check if the stored code must belong to a LG6711A20083V model. +/// @return true, if it is LG6711A20083V message. Otherwise, false. +/// @note Internal use only. +bool IRLgAc::_isLG6711A20083V(void) const { return isSwingVToggle(); } /// Get a copy of the internal state/code for this protocol. /// @return The code for this protocol based on the current internal state. @@ -353,7 +361,10 @@ void IRLgAc::setRaw(const uint32_t new_code, const decode_type_t protocol) { // Set the default model for this protocol, if the protocol is supplied. switch (protocol) { case decode_type_t::LG: - setModel(lg_ac_remote_model_t::GE6711AR2853M); + if (isSwingVToggle()) // This model uses a swingv toggle message. + setModel(lg_ac_remote_model_t::LG6711A20083V); + else // Assume others are a different model. + setModel(lg_ac_remote_model_t::GE6711AR2853M); break; case decode_type_t::LG2: setModel(lg_ac_remote_model_t::AKB75215403); @@ -521,18 +532,22 @@ void IRLgAc::setMode(const uint8_t mode) { } } +/// Check if the stored code is a SwingV Toggle message. +/// @return true, if it is. Otherwise, false. +bool IRLgAc::isSwingVToggle(void) const { return _.raw == kLgAcSwingVToggle; } + /// Check if the stored code is a Swing message. /// @return true, if it is. Otherwise, false. bool IRLgAc::isSwing(void) const { - return (_.raw >> 12) == kLgAcSwingSignature; + return ((_.raw >> 12) == kLgAcSwingSignature) || isSwingVToggle(); } /// Check if the stored code is a non-vane SwingV message. /// @return true, if it is. Otherwise, false. bool IRLgAc::isSwingV(void) const { const uint32_t code = _.raw >> kLgAcChecksumSize; - return code >= (kLgAcSwingVLowest >> kLgAcChecksumSize) && - code < (kLgAcSwingHAuto >> kLgAcChecksumSize); + return (code >= (kLgAcSwingVLowest >> kLgAcChecksumSize) && + code < (kLgAcSwingHAuto >> kLgAcChecksumSize)) || isSwingVToggle(); } /// Check if the stored code is a SwingH message. @@ -562,7 +577,7 @@ bool IRLgAc::isVaneSwingV(void) const { /// @param[in] position The position/mode to set the vanes to. void IRLgAc::setSwingV(const uint32_t position) { // Is it a valid position code? - if (position == kLgAcSwingVOff || + if (position == kLgAcSwingVOff || position == kLgAcSwingVToggle || toCommonSwingV(position) != stdAc::swingv_t::kOff) { if (position <= 0xFF) { // It's a short code, convert it. _swingv = (kLgAcSwingSignature << 8 | position) << kLgAcChecksumSize; @@ -703,6 +718,7 @@ stdAc::swingv_t IRLgAc::toCommonSwingV(const uint32_t code) { case kLgAcSwingVLow: return stdAc::swingv_t::kLow; case kLgAcSwingVLowest_Short: case kLgAcSwingVLowest: return stdAc::swingv_t::kLowest; + case kLgAcSwingVToggle: case kLgAcSwingVSwing_Short: case kLgAcSwingVSwing: return stdAc::swingv_t::kAuto; default: return stdAc::swingv_t::kOff; @@ -805,18 +821,21 @@ String IRLgAc::toString(void) const { } else if (isSwingH()) { result += addBoolToString(_swingh, kSwingHStr); } else if (isSwingV()) { - result += addSwingVToString((uint8_t)(_swingv >> kLgAcChecksumSize), - 0, // No Auto, See "swing". Unused - kLgAcSwingVHighest_Short, - kLgAcSwingVHigh_Short, - kLgAcSwingVUpperMiddle_Short, - kLgAcSwingVMiddle_Short, - 0, // Unused - kLgAcSwingVLow_Short, - kLgAcSwingVLowest_Short, - kLgAcSwingVOff_Short, - kLgAcSwingVSwing_Short, - 0, 0); + if (isSwingVToggle()) + result += addToggleToString(isSwingVToggle(), kSwingVStr); + else + result += addSwingVToString((uint8_t)(_swingv >> kLgAcChecksumSize), + 0, // No Auto, See "swing". Unused + kLgAcSwingVHighest_Short, + kLgAcSwingVHigh_Short, + kLgAcSwingVUpperMiddle_Short, + kLgAcSwingVMiddle_Short, + 0, // Unused + kLgAcSwingVLow_Short, + kLgAcSwingVLowest_Short, + kLgAcSwingVOff_Short, + kLgAcSwingVSwing_Short, + 0, 0); } else if (isVaneSwingV()) { const uint8_t vane = getVaneCode(_.raw) / kLgAcVaneSwingVSize; result += addIntToString(vane, kVaneStr); diff --git a/src/ir_LG.h b/src/ir_LG.h index 2bd7dbc1c..be33f4053 100644 --- a/src/ir_LG.h +++ b/src/ir_LG.h @@ -6,7 +6,8 @@ /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1513 // Supports: -// Brand: LG, Model: 6711A20083V remote (LG) +// Brand: LG, Model: 6711A20083V remote (LG - LG6711A20083V) +// Brand: LG, Model: TS-H122ERM1 remote (LG - LG6711A20083V) // Brand: LG, Model: AKB74395308 remote (LG2) // Brand: LG, Model: S4-W12JA3AA A/C (LG2) // Brand: LG, Model: AKB75215403 remote (LG2) @@ -17,8 +18,8 @@ // Brand: LG, Model: AKB73757604 remote (LG2 - AKB73757604) // Brand: LG, Model: AKB73315611 remote (LG2 - AKB74955603) // Brand: LG, Model: MS05SQ NW0 A/C (LG2 - AKB74955603) -// Brand: General Electric, Model: AG1BH09AW101 Split A/C (LG) -// Brand: General Electric, Model: 6711AR2853M A/C Remote (LG) +// Brand: General Electric, Model: AG1BH09AW101 A/C (LG - GE6711AR2853M) +// Brand: General Electric, Model: 6711AR2853M Remote (LG - GE6711AR2853M) #ifndef IR_LG_H_ #define IR_LG_H_ @@ -83,6 +84,7 @@ const uint32_t kLgAcSwingVHighest = 0x881309D; const uint32_t kLgAcSwingVSwing = 0x8813149; const uint32_t kLgAcSwingVAuto = kLgAcSwingVSwing; const uint32_t kLgAcSwingVOff = 0x881315A; +const uint32_t kLgAcSwingVToggle = 0x8810001; const uint8_t kLgAcSwingVLowest_Short = 0x04; const uint8_t kLgAcSwingVLow_Short = 0x05; const uint8_t kLgAcSwingVMiddle_Short = 0x06; @@ -144,6 +146,7 @@ class IRLgAc { void setSwingH(const bool on); bool getSwingH(void) const; bool isSwingV(void) const; + bool isSwingVToggle(void) const; bool isVaneSwingV(void) const; void setSwingV(const uint32_t position); uint32_t getSwingV(void) const; @@ -192,6 +195,7 @@ class IRLgAc { void _setTemp(const uint8_t value); bool _isAKB74955603(void) const; bool _isAKB73757604(void) const; + bool _isLG6711A20083V(void) const; bool _isNormal(void) const; }; diff --git a/src/locale/defaults.h b/src/locale/defaults.h index 4fb188f6c..015799784 100644 --- a/src/locale/defaults.h +++ b/src/locale/defaults.h @@ -608,6 +608,9 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_AKB73757604 #define D_STR_AKB73757604 "AKB73757604" #endif // D_STR_AKB73757604 +#ifndef D_STR_LG6711A20083V +#define D_STR_LG6711A20083V "LG6711A20083V" +#endif // D_STR_LG6711A20083V #ifndef D_STR_KKG9AC1 #define D_STR_KKG9AC1 "KKG9AC1" #endif // D_STR_KKG9AC1 diff --git a/test/ir_LG_test.cpp b/test/ir_LG_test.cpp index e93e7ea9e..078d1ecc6 100644 --- a/test/ir_LG_test.cpp +++ b/test/ir_LG_test.cpp @@ -693,6 +693,10 @@ TEST(TestUtils, Housekeeping) { IRac::strToModel(irutils::modelToStr( decode_type_t::LG2, lg_ac_remote_model_t::AKB73757604).c_str())); + ASSERT_EQ(lg_ac_remote_model_t::LG6711A20083V, + IRac::strToModel(irutils::modelToStr( + decode_type_t::LG, + lg_ac_remote_model_t::LG6711A20083V).c_str())); } TEST(TestIRLgAcClass, KnownExamples) { @@ -1163,3 +1167,20 @@ TEST(TestIRLgAcClass, Issue1737) { ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); EXPECT_TRUE(result.power); } + +TEST(TestIRLgAcClass, SwingVToggle) { + IRLgAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(lg_ac_remote_model_t::GE6711AR2853M); + EXPECT_FALSE(ac.isSwingVToggle()); + EXPECT_FALSE(ac._isLG6711A20083V()); + EXPECT_EQ(lg_ac_remote_model_t::GE6711AR2853M, ac.getModel()); + + ac.setRaw(kLgAcSwingVToggle, decode_type_t::LG); + EXPECT_TRUE(ac.isSwingVToggle()); + EXPECT_TRUE(ac._isLG6711A20083V()); + EXPECT_EQ(lg_ac_remote_model_t::LG6711A20083V, ac.getModel()); + + EXPECT_EQ("Model: 5 (LG6711A20083V), Swing(V): Toggle", ac.toString()); +} From 0f1f234aca971226e76b644895128dfec7014f73 Mon Sep 17 00:00:00 2001 From: crankyoldgit Date: Mon, 7 Mar 2022 23:01:42 +1000 Subject: [PATCH 2/3] More tests & handle IRac sending better. For #1770 --- src/IRac.cpp | 6 ++++++ test/ir_LG_test.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/IRac.cpp b/src/IRac.cpp index 45c288fee..650037de0 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -1509,6 +1509,12 @@ void IRac::lg(IRLgAc *ac, const lg_ac_remote_model_t model, const uint8_t pos = ac->convertVaneSwingV(swingv); for (uint8_t vane = 0; vane < kLgAcSwingVMaxVanes; vane++) ac->setVaneSwingV(vane, pos); + // Toggle the swingv for LG6711A20083V models if we need to. + // i.e. Off to Not-Off, send a toggle. Not-Off to Off, send a toggle. + if ((model == lg_ac_remote_model_t::LG6711A20083V) && + ((swingv == stdAc::swingv_t::kOff) != + (swingv_prev == stdAc::swingv_t::kOff))) + ac->setSwingV(kLgAcSwingVToggle); ac->setSwingH(swingh != stdAc::swingh_t::kOff); // No Quiet setting available. // No Turbo setting available. diff --git a/test/ir_LG_test.cpp b/test/ir_LG_test.cpp index 078d1ecc6..9652f702c 100644 --- a/test/ir_LG_test.cpp +++ b/test/ir_LG_test.cpp @@ -1183,4 +1183,10 @@ TEST(TestIRLgAcClass, SwingVToggle) { EXPECT_EQ(lg_ac_remote_model_t::LG6711A20083V, ac.getModel()); EXPECT_EQ("Model: 5 (LG6711A20083V), Swing(V): Toggle", ac.toString()); + + ac.stateReset(); + ac.setModel(lg_ac_remote_model_t::LG6711A20083V); + ac.setSwingV(kLgAcSwingVToggle); + EXPECT_EQ(ac._swingv, kLgAcSwingVToggle); + EXPECT_NE(ac._swingv_prev, kLgAcSwingVToggle); } From 71a8c302c60487350606f9130d7088902f6ba7dc Mon Sep 17 00:00:00 2001 From: crankyoldgit Date: Wed, 9 Mar 2022 18:12:43 +1000 Subject: [PATCH 3/3] Sort the Swing codes numerically. Per code review feedback. --- src/ir_LG.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ir_LG.h b/src/ir_LG.h index be33f4053..4f88ed2a8 100644 --- a/src/ir_LG.h +++ b/src/ir_LG.h @@ -74,6 +74,7 @@ const uint8_t kLgAcSignature = 0x88; const uint32_t kLgAcOffCommand = 0x88C0051; const uint32_t kLgAcLightToggle = 0x88C00A6; +const uint32_t kLgAcSwingVToggle = 0x8810001; const uint32_t kLgAcSwingSignature = 0x8813; const uint32_t kLgAcSwingVLowest = 0x8813048; const uint32_t kLgAcSwingVLow = 0x8813059; @@ -84,7 +85,6 @@ const uint32_t kLgAcSwingVHighest = 0x881309D; const uint32_t kLgAcSwingVSwing = 0x8813149; const uint32_t kLgAcSwingVAuto = kLgAcSwingVSwing; const uint32_t kLgAcSwingVOff = 0x881315A; -const uint32_t kLgAcSwingVToggle = 0x8810001; const uint8_t kLgAcSwingVLowest_Short = 0x04; const uint8_t kLgAcSwingVLow_Short = 0x05; const uint8_t kLgAcSwingVMiddle_Short = 0x06;