From 11a14c681377a8cc43742399b0c9e840568b7d0f Mon Sep 17 00:00:00 2001 From: Mateusz Bronk Date: Sat, 19 Nov 2022 15:45:58 +0100 Subject: [PATCH] Added "commandType" to IRAc Allows supporting A/C IR remote protocols which use different commands for representing slices of functionality. By default, all IRac commands are of type ac_command_t::kControlCommand Added Argo WREM3 implementation which uses disjoint commands. Signed-off-by: Mateusz Bronk --- src/IRac.cpp | 127 +++++++++++++++++++++++++++++++-- src/IRac.h | 8 +++ src/IRsend.h | 13 ++++ src/IRtext.cpp | 2 + src/IRtext.h | 2 + src/ir_Argo.cpp | 47 ++++++++++++- src/ir_Argo.h | 2 + src/locale/defaults.h | 6 ++ test/IRac_test.cpp | 106 ++++++++++++++++++++++++++++ test/ir_Argo_test.cpp | 158 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 465 insertions(+), 6 deletions(-) diff --git a/src/IRac.cpp b/src/IRac.cpp index f341e3afb..160b6d5ff 100644 --- a/src/IRac.cpp +++ b/src/IRac.cpp @@ -529,6 +529,72 @@ void IRac::argoWrem3_ACCommand(IRArgoAC_WREM3 *ac, const bool on, // No Beep setting available - always beeps in this mode :) ac->send(); } + +/// Send an Argo A/C WREM-3 iFeel (room temp) silent (no beep) report. +/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use. +/// @param[in] sensorTemp The room (iFeel) temperature setting +/// in degrees Celsius. +void IRac::argoWrem3_iFeelReport(IRArgoAC_WREM3 *ac, const float sensorTemp) { + ac->begin(); + ac->setMessageType(argoIrMessageType_t::IFEEL_TEMP_REPORT); + ac->setSensorTemp(sensorTemp); + ac->send(); +} + +/// Send an Argo A/C WREM-3 Config command. +/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use. +/// @param[in] param The parameter ID. +/// @param[in] value The parameter value. +/// @param[in] safe If true, will only allow setting the below parameters +/// in order to avoid accidentally setting a restricted +/// vendor-specific param and breaking the A/C device +/// @note Known parameters (P, where xx is the @c param) +/// P05 - Temperature Scale (0-Celsius, 1-Fahrenheit) +/// P06 - Transmission channel (0..3) +/// P12 - ECO mode power input limit (30..99, default: 75) +void IRac::argoWrem3_ConfigSet(IRArgoAC_WREM3 *ac, const uint8_t param, + const uint8_t value, bool safe /*= true*/) { + if (safe) { + switch (param) { + case 5: // temp. scale (note this is likely excess as not transmitted) + if (value > 1) { return; /* invalid */ } + break; + case 6: // channel (note this is likely excess as not transmitted) + if (value > 3) { return; /* invalid */ } + break; + case 12: // eco power limit + if (value < 30 || value > 99) { return; /* invalid */ } + break; + default: + return; /* invalid */ + } + } + ac->begin(); + ac->setMessageType(argoIrMessageType_t::CONFIG_PARAM_SET); + ac->setConfigEntry(param, value); + ac->send(); +} + +/// Send an Argo A/C WREM-3 Delay timer command. +/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use. +/// @param[in] on Whether the unit is currently on. The timer, upon elapse +/// will toggle this state +/// @param[in] currentTime currentTime in minutes, starting from 00:00 +/// @note For timer mode, this value is not really used much so can be zero. +/// @param[in] delayMinutes Number of minutes after which the @c on state should +/// be toggled +/// @note Schedule timers are not exposed via this interface +void IRac::argoWrem3_SetTimer(IRArgoAC_WREM3 *ac, bool on, + const uint16_t currentTime, const uint16_t delayMinutes) { + ac->begin(); + ac->setMessageType(argoIrMessageType_t::TIMER_COMMAND); + ac->setPower(on); + ac->setTimerType(argoTimerType_t::DELAY_TIMER); + ac->setCurrentTimeMinutes(currentTime); + // Note: Day of week is not set (no need) + ac->setDelayTimerMinutes(delayMinutes); + ac->send(); +} #endif // SEND_ARGO #if SEND_BOSCH144 @@ -2917,9 +2983,28 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { if (send.model == argo_ac_remote_model_t::SAC_WREM3) { IRArgoAC_WREM3 ac(_pin, _inverted, _modulation); - argoWrem3_ACCommand(&ac, send.power, send.mode, send.degrees, - send.fanspeed, send.swingv, send.quiet, send.econo, send.turbo, - send.filter, send.light); + switch (send.command) { + case stdAc::ac_command_t::kSensorTempReport: + argoWrem3_iFeelReport(&ac, send.degrees); // Uses "degrees" + // as roomTemp + break; + case stdAc::ac_command_t::kConfigCommand: + /// @warning: this is ABUSING current **common** parameters: + /// @c clock and @c sleep as config key and value + /// Hence, value pre-validation is performed (safe-mode) + /// to avoid accidental device misconfiguration + argoWrem3_ConfigSet(&ac, send.clock, send.sleep, true); + break; + case stdAc::ac_command_t::kTimerCommand: + argoWrem3_SetTimer(&ac, send.power, send.clock, send.sleep); + break; + case stdAc::ac_command_t::kControlCommand: + default: + argoWrem3_ACCommand(&ac, send.power, send.mode, send.degrees, + send.fanspeed, send.swingv, send.quiet, send.econo, send.turbo, + send.filter, send.light); + break; + } OUTPUT_DECODE_RESULTS_FOR_UT(ac); } else { IRArgoAC ac(_pin, _inverted, _modulation); @@ -3495,7 +3580,8 @@ bool IRac::cmpStates(const stdAc::state_t a, const stdAc::state_t b) { a.fanspeed != b.fanspeed || a.swingv != b.swingv || a.swingh != b.swingh || a.quiet != b.quiet || a.turbo != b.turbo || a.econo != b.econo || a.light != b.light || a.filter != b.filter || - a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep; + a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep || + a.command != b.command; } /// Check if the internal state has changed from what was previously sent. @@ -3503,6 +3589,26 @@ bool IRac::cmpStates(const stdAc::state_t a, const stdAc::state_t b) { /// @return True if it has changed, False if not. bool IRac::hasStateChanged(void) { return cmpStates(next, _prev); } +/// Convert the supplied str into the appropriate enum. +/// @param[in] str A Ptr to a C-style string to be converted. +/// @param[in] def The enum to return if no conversion was possible. +/// @return The equivalent enum. +stdAc::ac_command_t IRac::strToCommandType(const char *str, + const stdAc::ac_command_t def) { + if (!STRCASECMP(str, kControlCommandStr)) + return stdAc::ac_command_t::kControlCommand; + else if (!STRCASECMP(str, kIFeelReportStr) || + !STRCASECMP(str, kIFeelStr)) + return stdAc::ac_command_t::kSensorTempReport; + else if (!STRCASECMP(str, kSetTimerCommandStr) || + !STRCASECMP(str, kTimerStr)) + return stdAc::ac_command_t::kTimerCommand; + else if (!STRCASECMP(str, kConfigCommandStr)) + return stdAc::ac_command_t::kConfigCommand; + else + return def; +} + /// Convert the supplied str into the appropriate enum. /// @param[in] str A Ptr to a C-style string to be converted. /// @param[in] def The enum to return if no conversion was possible. @@ -3780,6 +3886,19 @@ String IRac::boolToString(const bool value) { return value ? kOnStr : kOffStr; } +/// Convert the supplied operation mode into the appropriate String. +/// @param[in] cmdType The enum to be converted. +/// @return The equivalent String for the locale. +String IRac::commandTypeToString(const stdAc::ac_command_t cmdType) { + switch (cmdType) { + case stdAc::ac_command_t::kControlCommand: return kControlCommandStr; + case stdAc::ac_command_t::kSensorTempReport: return kIFeelReportStr; + case stdAc::ac_command_t::kTimerCommand: return kSetTimerCommandStr; + case stdAc::ac_command_t::kConfigCommand: return kConfigCommandStr; + default: return kUnknownStr; + } +} + /// Convert the supplied operation mode into the appropriate String. /// @param[in] mode The enum to be converted. /// @param[in] ha A flag to indicate we want GoogleHome/HomeAssistant output. diff --git a/src/IRac.h b/src/IRac.h index 5545a26fa..e69dd3b19 100644 --- a/src/IRac.h +++ b/src/IRac.h @@ -86,6 +86,8 @@ class IRac { static bool cmpStates(const stdAc::state_t a, const stdAc::state_t b); static bool strToBool(const char *str, const bool def = false); static int16_t strToModel(const char *str, const int16_t def = -1); + static stdAc::ac_command_t strToCommandType(const char *str, + const stdAc::ac_command_t def = stdAc::ac_command_t::kControlCommand); static stdAc::opmode_t strToOpmode( const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto); static stdAc::fanspeed_t strToFanspeed( @@ -96,6 +98,7 @@ class IRac { static stdAc::swingh_t strToSwingH( const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff); static String boolToString(const bool value); + static String commandTypeToString(const stdAc::ac_command_t cmdType); static String opmodeToString(const stdAc::opmode_t mode, const bool ha = false); static String fanspeedToString(const stdAc::fanspeed_t speed); @@ -148,6 +151,11 @@ class IRac { const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool night, const bool econo, const bool turbo, const bool filter, const bool light); + void argoWrem3_iFeelReport(IRArgoAC_WREM3 *ac, const float sensorTemp); + void argoWrem3_ConfigSet(IRArgoAC_WREM3 *ac, const uint8_t param, + const uint8_t value, bool safe = true); + void argoWrem3_SetTimer(IRArgoAC_WREM3 *ac, bool on, + const uint16_t currentTime, const uint16_t delayMinutes); #endif // SEND_ARGO #if SEND_BOSCH144 void bosch144(IRBosch144AC *ac, diff --git a/src/IRsend.h b/src/IRsend.h index f67f9cf00..c90d7a483 100644 --- a/src/IRsend.h +++ b/src/IRsend.h @@ -79,6 +79,18 @@ enum class swingv_t { kLastSwingvEnum = kLowest, }; +/// @brief Tyoe of A/C command (if the remote uses different codes for each) +/// @note Most remotes support only a single command or aggregate multiple +/// into one (e.g. control+timer). Use @c kControlCommand in such case +enum class ac_command_t { + kControlCommand = 0, + kSensorTempReport = 1, + kTimerCommand = 2, + kConfigCommand = 3, + // Add new entries before this one, and update it to point to the last entry + kLastAcCommandEnum = kConfigCommand, +}; + /// Common A/C settings for Horizontal Swing. enum class swingh_t { kOff = -1, @@ -113,6 +125,7 @@ struct state_t { bool beep = false; int16_t sleep = -1; // `-1` means off. int16_t clock = -1; // `-1` means not set. + stdAc::ac_command_t command = stdAc::ac_command_t::kControlCommand; }; }; // namespace stdAc diff --git a/src/IRtext.cpp b/src/IRtext.cpp index f4e6291f9..9af6e381c 100644 --- a/src/IRtext.cpp +++ b/src/IRtext.cpp @@ -69,6 +69,7 @@ IRTEXT_CONST_STRING(kTimerModeStr, D_STR_TIMERMODE); ///< "Timer Mode" IRTEXT_CONST_STRING(kClockStr, D_STR_CLOCK); ///< "Clock" IRTEXT_CONST_STRING(kCommandStr, D_STR_COMMAND); ///< "Command" IRTEXT_CONST_STRING(kConfigCommandStr, D_STR_CONFIG); ///< "Config" +IRTEXT_CONST_STRING(kControlCommandStr, D_STR_CONTROL); ///< "Control" IRTEXT_CONST_STRING(kXFanStr, D_STR_XFAN); ///< "XFan" IRTEXT_CONST_STRING(kHealthStr, D_STR_HEALTH); ///< "Health" IRTEXT_CONST_STRING(kModelStr, D_STR_MODEL); ///< "Model" @@ -208,6 +209,7 @@ IRTEXT_CONST_STRING(kSwingVModeStr, D_STR_SWINGVMODE); ///< "Swing(V) Mode" IRTEXT_CONST_STRING(kSwingVToggleStr, D_STR_SWINGVTOGGLE); ///< ///< "Swing(V) Toggle" IRTEXT_CONST_STRING(kTurboToggleStr, D_STR_TURBOTOGGLE); ///< "Turbo Toggle" +IRTEXT_CONST_STRING(kSetTimerCommandStr, D_STR_SET_TIMER); ///< "Set Timer" IRTEXT_CONST_STRING(kScheduleStr, D_STR_SCHEDULE); ///< "Schedule" IRTEXT_CONST_STRING(kChStr, D_STR_CH); ///< "CH#" IRTEXT_CONST_STRING(kTimerActiveDaysStr, D_STR_TIMER_ACTIVE_DAYS); diff --git a/src/IRtext.h b/src/IRtext.h index d8ab89900..c99081ab2 100644 --- a/src/IRtext.h +++ b/src/IRtext.h @@ -70,6 +70,7 @@ extern IRTEXT_CONST_PTR(kComfortStr); extern IRTEXT_CONST_PTR(kCommaSpaceStr); extern IRTEXT_CONST_PTR(kCommandStr); extern IRTEXT_CONST_PTR(kConfigCommandStr); +extern IRTEXT_CONST_PTR(kControlCommandStr); extern IRTEXT_CONST_PTR(kCoolStr); extern IRTEXT_CONST_PTR(kCoolingStr); extern IRTEXT_CONST_PTR(kDashStr); @@ -224,6 +225,7 @@ extern IRTEXT_CONST_PTR(kTempUpStr); extern IRTEXT_CONST_PTR(kThreeLetterDayOfWeekStr); extern IRTEXT_CONST_PTR(kTimerActiveDaysStr); extern IRTEXT_CONST_PTR(kTimerModeStr); +extern IRTEXT_CONST_PTR(kSetTimerCommandStr); extern IRTEXT_CONST_PTR(kTimerStr); extern IRTEXT_CONST_PTR(kToggleStr); extern IRTEXT_CONST_PTR(kTopStr); diff --git a/src/ir_Argo.cpp b/src/ir_Argo.cpp index d36c6ad54..c55819def 100644 --- a/src/ir_Argo.cpp +++ b/src/ir_Argo.cpp @@ -1044,6 +1044,25 @@ uint8_t IRArgoACBase::getSensorTemp(void) const { return _.RoomTemp + kArgoTempDelta; } +/// @brief Convert a stdAc::ac_command_t enum into its native message type. +/// @param command The enum to be converted. +/// @return The native equivalent of the enum. +template +argoIrMessageType_t IRArgoACBase::convertCommand( + const stdAc::ac_command_t command) { + switch (command) { + case stdAc::ac_command_t::kSensorTempReport: + return argoIrMessageType_t::IFEEL_TEMP_REPORT; + case stdAc::ac_command_t::kTimerCommand: + return argoIrMessageType_t::TIMER_COMMAND; + case stdAc::ac_command_t::kConfigCommand: + return argoIrMessageType_t::CONFIG_PARAM_SET; + case stdAc::ac_command_t::kControlCommand: + default: + return argoIrMessageType_t::AC_CONTROL; + } +} + /// Convert a stdAc::opmode_t enum into its native mode. /// @param[in] mode The enum to be converted. /// @return The native equivalent of the enum. @@ -1169,6 +1188,26 @@ stdAc::swingv_t IRArgoACBase::toCommonSwingV( } } +/// Convert a native message type into its stdAc equivalent. +/// @param[in] command The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +template +stdAc::ac_command_t IRArgoACBase::toCommonCommand( + const argoIrMessageType_t command) { + switch (command) { + case argoIrMessageType_t::AC_CONTROL: + return stdAc::ac_command_t::kControlCommand; + case argoIrMessageType_t::IFEEL_TEMP_REPORT: + return stdAc::ac_command_t::kSensorTempReport; + case argoIrMessageType_t::TIMER_COMMAND: + return stdAc::ac_command_t::kTimerCommand; + case argoIrMessageType_t::CONFIG_PARAM_SET: + return stdAc::ac_command_t::kConfigCommand; + default: + return stdAc::ac_command_t::kControlCommand; + } +} + /// Convert a native mode into its stdAc equivalent. /// @param[in] mode The native setting to be converted. /// @return The stdAc equivalent of the native setting. @@ -1208,10 +1247,12 @@ stdAc::state_t IRArgoAC::toCommon(void) const { stdAc::state_t result{}; result.protocol = decode_type_t::ARGO; result.model = argo_ac_remote_model_t::SAC_WREM2; + result.command = toCommonCommand(_messageType); result.power = _.Power; result.mode = toCommonMode(getModeEx()); result.celsius = true; - result.degrees = getTemp(); + result.degrees = (_messageType != argoIrMessageType_t::IFEEL_TEMP_REPORT)? + getTemp() : getSensorTemp(); result.fanspeed = toCommonFanSpeed(getFanEx()); result.turbo = _.Max; result.sleep = _.Night ? 0 : -1; @@ -1235,10 +1276,12 @@ stdAc::state_t IRArgoAC_WREM3::toCommon(void) const { stdAc::state_t result{}; result.protocol = decode_type_t::ARGO; result.model = argo_ac_remote_model_t::SAC_WREM3; + result.command = toCommonCommand(_messageType); result.power = getPower(); result.mode = toCommonMode(getModeEx()); result.celsius = true; - result.degrees = getTemp(); + result.degrees = (_messageType != argoIrMessageType_t::IFEEL_TEMP_REPORT)? + getTemp() : getSensorTemp(); result.fanspeed = toCommonFanSpeed(getFanEx()); result.turbo = _.Max; result.swingv = toCommonSwingV(_.Flap); diff --git a/src/ir_Argo.h b/src/ir_Argo.h index 432dfe4f7..ba804f93c 100644 --- a/src/ir_Argo.h +++ b/src/ir_Argo.h @@ -381,6 +381,7 @@ class IRArgoACBase { static argoMode_t convertMode(const stdAc::opmode_t mode); static argoFan_t convertFan(const stdAc::fanspeed_t speed); static argoFlap_t convertSwingV(const stdAc::swingv_t position); + static argoIrMessageType_t convertCommand(const stdAc::ac_command_t command); protected: void _stateReset(ARGO_PROTOCOL_T *state, argoIrMessageType_t messageType @@ -397,6 +398,7 @@ class IRArgoACBase { static stdAc::opmode_t toCommonMode(const argoMode_t mode); static stdAc::fanspeed_t toCommonFanSpeed(const argoFan_t speed); static stdAc::swingv_t toCommonSwingV(const uint8_t position); + static stdAc::ac_command_t toCommonCommand(const argoIrMessageType_t command); // Attributes ARGO_PROTOCOL_T _; ///< The raw protocol data diff --git a/src/locale/defaults.h b/src/locale/defaults.h index 9bd3cce9e..a5f6aee8d 100644 --- a/src/locale/defaults.h +++ b/src/locale/defaults.h @@ -454,6 +454,12 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_CONFIG #define D_STR_CONFIG "Config" #endif // D_STR_CONFIG +#ifndef D_STR_CONTROL +#define D_STR_CONTROL "Control" +#endif // D_STR_CONTROL +#ifndef D_STR_SET_TIMER +#define D_STR_SET_TIMER D_STR_SET " " D_STR_TIMER +#endif // D_STR_AC_TIMER #ifndef D_STR_SCHEDULE #define D_STR_SCHEDULE "Schedule" #endif // D_STR_SCHEDULE diff --git a/test/IRac_test.cpp b/test/IRac_test.cpp index 32df445ac..c3732cb66 100644 --- a/test/IRac_test.cpp +++ b/test/IRac_test.cpp @@ -73,6 +73,7 @@ TEST(TestIRac, Airton) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Airwell) { @@ -96,6 +97,7 @@ TEST(TestIRac, Airwell) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Amcor) { @@ -119,6 +121,7 @@ TEST(TestIRac, Amcor) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Argo) { @@ -140,6 +143,7 @@ TEST(TestIRac, Argo) { EXPECT_EQ(kArgoFlapFull, ac.getFlap()); EXPECT_FALSE(ac.getMax()); // Turbo EXPECT_FALSE(ac.getNight()); // Sleep + EXPECT_EQ(argoIrMessageType_t::AC_CONTROL, ac.getMessageType()); } TEST(TestIRac, Carrier64) { @@ -174,6 +178,7 @@ TEST(TestIRac, Carrier64) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Coolix) { @@ -235,6 +240,7 @@ TEST(TestIRac, Coolix) { // End of message #2 (i.e. Repeat '1') // Note: the two messages (#1 & #2) are identical. ac._irsend.outputStr()); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Corona) { @@ -277,6 +283,7 @@ TEST(TestIRac, Corona) { ASSERT_EQ(expectedCapture, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin) { @@ -310,6 +317,7 @@ TEST(TestIRac, Daikin) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin128) { @@ -343,6 +351,7 @@ TEST(TestIRac, Daikin128) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin152) { @@ -371,6 +380,7 @@ TEST(TestIRac, Daikin152) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin160) { @@ -396,6 +406,7 @@ TEST(TestIRac, Daikin160) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin176) { @@ -421,6 +432,7 @@ TEST(TestIRac, Daikin176) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin2) { @@ -460,6 +472,7 @@ TEST(TestIRac, Daikin2) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin216) { @@ -488,6 +501,7 @@ TEST(TestIRac, Daikin216) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Daikin64) { @@ -656,6 +670,7 @@ TEST(TestIRac, Fujitsu) { ASSERT_EQ(ardb1_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); // Try to set the device to 10C Heat mode. @@ -681,6 +696,7 @@ TEST(TestIRac, Fujitsu) { ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits); ASSERT_EQ(arrah2e_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); irac.fujitsu(&ac, fujitsu_ac_remote_model_t::ARRY4, // Model @@ -703,6 +719,7 @@ TEST(TestIRac, Fujitsu) { ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits); ASSERT_EQ(arry4_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); irac.fujitsu(&ac, @@ -753,6 +770,7 @@ TEST(TestIRac, Goodweather) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Gree) { @@ -789,6 +807,7 @@ TEST(TestIRac, Gree) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Haier) { @@ -818,6 +837,7 @@ TEST(TestIRac, Haier) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Haier160) { @@ -853,6 +873,7 @@ TEST(TestIRac, Haier160) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Haier176) { @@ -886,6 +907,7 @@ TEST(TestIRac, Haier176) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, HaierYrwo2) { @@ -919,6 +941,7 @@ TEST(TestIRac, HaierYrwo2) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Hitachi) { @@ -946,6 +969,7 @@ TEST(TestIRac, Hitachi) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Hitachi1) { @@ -978,6 +1002,7 @@ TEST(TestIRac, Hitachi1) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Hitachi264) { @@ -1003,6 +1028,7 @@ TEST(TestIRac, Hitachi264) { ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); EXPECT_EQ(decode_type_t::HITACHI_AC264, r.protocol); EXPECT_TRUE(r.power); EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode); @@ -1031,6 +1057,7 @@ TEST(TestIRac, Hitachi296) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); EXPECT_EQ(decode_type_t::HITACHI_AC296, r.protocol); EXPECT_TRUE(r.power); EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode); @@ -1062,6 +1089,7 @@ TEST(TestIRac, Hitachi344) { ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); EXPECT_EQ(decode_type_t::HITACHI_AC344, r.protocol); EXPECT_TRUE(r.power); EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode); @@ -1082,6 +1110,7 @@ TEST(TestIRac, Hitachi344) { ASSERT_EQ(expected_swingoff, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ASSERT_EQ(HITACHI_AC344, ac._irsend.capture.decode_type); ASSERT_EQ(kHitachiAc344Bits, ac._irsend.capture.bits); ASSERT_EQ(expected_swingoff, @@ -1115,6 +1144,7 @@ TEST(TestIRac, Hitachi424) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); irac.hitachi424(&ac, @@ -1131,6 +1161,7 @@ TEST(TestIRac, Hitachi424) { ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits); ASSERT_EQ(expected_swingv, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Kelvinator) { @@ -1164,6 +1195,7 @@ TEST(TestIRac, Kelvinator) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, LG) { @@ -1196,6 +1228,7 @@ TEST(TestIRac, LG) { ASSERT_EQ(61, ac._irsend.capture.rawlen); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, LG2) { @@ -1228,6 +1261,7 @@ TEST(TestIRac, LG2) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); // Message #2 - SwingV Low EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61)); ASSERT_EQ(LG2, ac._irsend.capture.decode_type); @@ -1443,6 +1477,7 @@ TEST(TestIRac, LG2_AKB73757604) { ASSERT_EQ(LG2, ac._irsend.capture.decode_type); ASSERT_EQ(kLgBits, ac._irsend.capture.bits); ASSERT_EQ(kLgAcSwingHAuto, ac._irsend.capture.value); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Midea) { @@ -1479,6 +1514,7 @@ TEST(TestIRac, Midea) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Mirage) { @@ -1518,6 +1554,7 @@ TEST(TestIRac, Mirage) { ASSERT_EQ(kMirageBits, ac._irsend.capture.bits); ASSERT_EQ(expected_KKG9AC1, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); const char expected_KKG29AC1[] = "Model: 2 (KKG29AC1), Power: On, Mode: 3 (Dry), Temp: 27C, " @@ -1535,6 +1572,7 @@ TEST(TestIRac, Mirage) { ASSERT_EQ(expected_KKG29AC1, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Mitsubishi) { @@ -1567,6 +1605,7 @@ TEST(TestIRac, Mitsubishi) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Mitsubishi136) { @@ -1593,6 +1632,7 @@ TEST(TestIRac, Mitsubishi136) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, MitsubishiHeavy88) { @@ -1623,6 +1663,7 @@ TEST(TestIRac, MitsubishiHeavy88) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, MitsubishiHeavy152) { @@ -1656,6 +1697,7 @@ TEST(TestIRac, MitsubishiHeavy152) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Neoclima) { @@ -1690,6 +1732,7 @@ TEST(TestIRac, Neoclima) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Panasonic) { @@ -1722,6 +1765,7 @@ TEST(TestIRac, Panasonic) { ASSERT_EQ(expected_nke, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); char expected_dke[] = "Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (Maximum), " @@ -1748,6 +1792,7 @@ TEST(TestIRac, Panasonic) { ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits); ASSERT_EQ(expected_dke, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Panasonic32) { @@ -1774,6 +1819,7 @@ TEST(TestIRac, Panasonic32) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Samsung) { @@ -1813,6 +1859,7 @@ TEST(TestIRac, Samsung) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); irac.samsung(&ac, @@ -1841,6 +1888,7 @@ TEST(TestIRac, Samsung) { ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); const char sleep[] = @@ -1874,6 +1922,7 @@ TEST(TestIRac, Samsung) { ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); ASSERT_EQ(sleep, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Sanyo) { @@ -1902,6 +1951,7 @@ TEST(TestIRac, Sanyo) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Sanyo88) { @@ -1931,6 +1981,7 @@ TEST(TestIRac, Sanyo88) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Sharp) { @@ -1963,6 +2014,7 @@ TEST(TestIRac, Sharp) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Tcl112) { @@ -1997,6 +2049,7 @@ TEST(TestIRac, Tcl112) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); // Test the quiet mode, which should generate two messages. ac._irsend.reset(); irac.tcl112(&ac, @@ -2052,6 +2105,7 @@ TEST(TestIRac, Technibel) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Teco) { @@ -2079,6 +2133,7 @@ TEST(TestIRac, Teco) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Toshiba) { @@ -2108,6 +2163,7 @@ TEST(TestIRac, Toshiba) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); EXPECT_EQ( "f38000d50" "m4400s4300" @@ -2183,6 +2239,7 @@ TEST(TestIRac, Transcold) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Trotec) { @@ -2212,6 +2269,7 @@ TEST(TestIRac, Trotec) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Trotec3550) { @@ -2242,6 +2300,7 @@ TEST(TestIRac, Trotec3550) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Truma) { @@ -2271,6 +2330,7 @@ TEST(TestIRac, Truma) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, Vestel) { @@ -2300,6 +2360,7 @@ TEST(TestIRac, Vestel) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); char expected_clocks[] = @@ -2325,6 +2386,7 @@ TEST(TestIRac, Vestel) { ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits); ASSERT_EQ(expected_clocks, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); // Now check it sends both messages during normal operation when the // clock is set. @@ -2404,6 +2466,7 @@ TEST(TestIRac, Voltas) { ASSERT_EQ(expected_unknown, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); ac._irsend.reset(); // Test the UNKNOWN model type @@ -2470,6 +2533,7 @@ TEST(TestIRac, Whirlpool) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } TEST(TestIRac, cmpStates) { @@ -2507,6 +2571,11 @@ TEST(TestIRac, cmpStates) { // Now make them different. b.power = false; ASSERT_TRUE(IRac::cmpStates(a, b)); + + b = a; + ASSERT_FALSE(IRac::cmpStates(a, b)); + b.command = stdAc::ac_command_t::kTimerCommand; + ASSERT_TRUE(IRac::cmpStates(a, b)); } TEST(TestIRac, handleToggles) { @@ -2663,6 +2732,26 @@ TEST(TestIRac, strToModel) { EXPECT_EQ(0, IRac::strToModel("FOOBAR", 0)); } +TEST(TestIRac, strToCommandType) { + EXPECT_EQ(stdAc::ac_command_t::kControlCommand, + IRac::strToCommandType("Control")); + EXPECT_EQ(stdAc::ac_command_t::kSensorTempReport, + IRac::strToCommandType("IFeel Report")); + EXPECT_EQ(stdAc::ac_command_t::kSensorTempReport, + IRac::strToCommandType("IFeel")); + EXPECT_EQ(stdAc::ac_command_t::kTimerCommand, + IRac::strToCommandType("Set Timer")); + EXPECT_EQ(stdAc::ac_command_t::kTimerCommand, + IRac::strToCommandType("Timer")); + EXPECT_EQ(stdAc::ac_command_t::kConfigCommand, + IRac::strToCommandType("Config")); + EXPECT_EQ(stdAc::ac_command_t::kControlCommand, + IRac::strToCommandType("FOOBAR")); + EXPECT_EQ(stdAc::ac_command_t::kTimerCommand, + IRac::strToCommandType("FOOBAR", + stdAc::ac_command_t::kTimerCommand)); +} + TEST(TestIRac, boolToString) { EXPECT_EQ("On", IRac::boolToString(true)); EXPECT_EQ("Off", IRac::boolToString(false)); @@ -2700,6 +2789,17 @@ TEST(TestIRac, swinghToString) { EXPECT_EQ("UNKNOWN", IRac::swinghToString((stdAc::swingh_t)500)); } +TEST(TestIRac, commandTypeToString) { + EXPECT_EQ("Control", + IRac::commandTypeToString(stdAc::ac_command_t::kControlCommand)); + EXPECT_EQ("IFeel Report", + IRac::commandTypeToString(stdAc::ac_command_t::kSensorTempReport)); + EXPECT_EQ("Set Timer", + IRac::commandTypeToString(stdAc::ac_command_t::kTimerCommand)); + EXPECT_EQ("Config", + IRac::commandTypeToString(stdAc::ac_command_t::kConfigCommand)); +} + // Check that we keep the previous state info if the message is a special // state-less command. TEST(TestIRac, CoolixDecodeToState) { @@ -2718,6 +2818,7 @@ TEST(TestIRac, CoolixDecodeToState) { ASSERT_TRUE(irrecv.decode(&irsend.capture)); stdAc::state_t result; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command); ASSERT_EQ(decode_type_t::COOLIX, result.protocol); ASSERT_FALSE(result.power); ASSERT_EQ(stdAc::opmode_t::kHeat, result.mode); @@ -2881,6 +2982,7 @@ TEST(TestIRac, Issue1001) { IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); // Now check if the mode is set to "Off" instead of just change to power off. // i.e. How Home Assistant expects things to work. @@ -2911,6 +3013,7 @@ TEST(TestIRac, Issue1001) { "Command: 1 (Power)", IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } // Check power switching in Daikin2 common a/c handling when from an IR message. @@ -2960,6 +3063,7 @@ TEST(TestIRac, Issue1035) { ASSERT_FALSE(prev.power); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev)); ASSERT_TRUE(result.power); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command); prev = result; @@ -2971,6 +3075,7 @@ TEST(TestIRac, Issue1035) { ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type); ASSERT_TRUE(prev.power); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev)); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command); ASSERT_FALSE(result.power); } @@ -3142,4 +3247,5 @@ TEST(TestIRac, initState) { EXPECT_EQ(-1, builtin_init.model); EXPECT_EQ(stdAc::swingv_t::kOff, builtin_init.swingv); EXPECT_EQ(decode_type_t::UNKNOWN, no_init.protocol); + EXPECT_EQ(stdAc::ac_command_t::kControlCommand, no_init.command); } diff --git a/test/ir_Argo_test.cpp b/test/ir_Argo_test.cpp index ed3404922..b18f1e808 100644 --- a/test/ir_Argo_test.cpp +++ b/test/ir_Argo_test.cpp @@ -25,6 +25,7 @@ TEST(TestArgoACClass, toCommon) { ac.setNight(true); // Now test it. ASSERT_EQ(decode_type_t::ARGO, ac.toCommon().protocol); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, ac.toCommon().command); ASSERT_TRUE(ac.toCommon().power); ASSERT_TRUE(ac.toCommon().celsius); ASSERT_EQ(20, ac.toCommon().degrees); @@ -61,6 +62,7 @@ TEST(TestArgoAC_WREM3Class, toCommon) { // Now test it. ASSERT_EQ(decode_type_t::ARGO, ac.toCommon().protocol); ASSERT_EQ(argo_ac_remote_model_t::SAC_WREM3, ac.toCommon().model); + ASSERT_EQ(stdAc::ac_command_t::kControlCommand, ac.toCommon().command); ASSERT_TRUE(ac.toCommon().celsius); ASSERT_TRUE(ac.toCommon().beep); // Always on (except for iFeel) ASSERT_FALSE(ac.toCommon().clean); @@ -398,6 +400,161 @@ TEST(TestIrAc, ArgoWrem3_SyntheticSendAndDecode_ACCommand) { EXPECT_EQ(state.power, r.power); } +TEST(TestIrAc, ArgoWrem3_SyntheticSendAndDecode_iFeelReport) { + IRac irac(kGpioUnused); + auto capture = std::make_shared(kGpioUnused); + irac._utReceiver = capture; + + stdAc::state_t state = {}; + state.protocol = ARGO; + state.model = argo_ac_remote_model_t::SAC_WREM3; + state.command = stdAc::ac_command_t::kSensorTempReport; + state.degrees = 19; + + irac.sendAc(state, nullptr); + + ASSERT_NE(nullptr, irac._lastDecodeResults); + EXPECT_EQ(ARGO, irac._lastDecodeResults->decode_type); + EXPECT_EQ("IFeel Report[CH#0]: Model: 2 (WREM3), Sensor Temp: 19C", + IRAcUtils::resultAcToString(irac._lastDecodeResults.get())); + + stdAc::state_t r = {}; + ASSERT_TRUE(IRAcUtils::decodeToState(irac._lastDecodeResults.get(), &r, + nullptr)); + EXPECT_EQ(ARGO, r.protocol); + EXPECT_EQ(state.model, r.model); + EXPECT_EQ(state.command, r.command); + EXPECT_EQ(state.degrees, r.degrees); +} + +TEST(TestIrAc, ArgoWrem3_SyntheticSendAndDecode_Timer) { + IRac irac(kGpioUnused); + auto capture = std::make_shared(kGpioUnused); + irac._utReceiver = capture; + + stdAc::state_t state = {}; + state.protocol = ARGO; + state.model = argo_ac_remote_model_t::SAC_WREM3; + state.command = stdAc::ac_command_t::kTimerCommand; + state.power = true; + state.mode = stdAc::opmode_t::kAuto; // Needs to be set for `state.power` + // not to be ignored! + state.clock = 13*60+21; + state.sleep = 2*60+10; + + irac.sendAc(state, nullptr); + + ASSERT_NE(nullptr, irac._lastDecodeResults); + EXPECT_EQ(ARGO, irac._lastDecodeResults->decode_type); + EXPECT_EQ("Timer[CH#0]: Model: 2 (WREM3), Power: On, Timer Mode: 1 " + "(Sleep Timer), Clock: 13:21, Day: 0 (Sun), Timer: 02:10", + IRAcUtils::resultAcToString(irac._lastDecodeResults.get())); + + stdAc::state_t r = {}; + ASSERT_TRUE(IRAcUtils::decodeToState(irac._lastDecodeResults.get(), &r, + nullptr)); + EXPECT_EQ(ARGO, r.protocol); + EXPECT_EQ(state.model, r.model); + EXPECT_EQ(state.command, r.command); + EXPECT_EQ(state.power, r.power); + EXPECT_EQ(state.clock, r.clock); + EXPECT_EQ(state.sleep, r.sleep); +} + +/// +/// @brief Test fixture for Config messages sent via @c IRAc generic i-face +/// @note The commands are abusing generic intafrace and instead are +/// using: @c clock -> for settingID +/// @c sleep -> for setting Value +/// +class TestArgoConfigViaIRAc : + public ::testing::TestWithParam> { +}; + +class TestArgoConfigViaIRAc_Positive : public TestArgoConfigViaIRAc {}; +TEST_P(TestArgoConfigViaIRAc_Positive, + ArgoWrem3_SyntheticSendAndDecode_Config_Positive) { + int16_t settingId = std::get<0>(GetParam()); + int16_t settingValue = std::get<1>(GetParam()); + IRac irac(kGpioUnused); + auto capture = std::make_shared(kGpioUnused); + irac._utReceiver = capture; + + stdAc::state_t state = {}; + state.protocol = ARGO; + state.model = argo_ac_remote_model_t::SAC_WREM3; + state.command = stdAc::ac_command_t::kConfigCommand; + state.clock = settingId; + state.sleep = settingValue; + + irac.sendAc(state, nullptr); + + ASSERT_NE(nullptr, irac._lastDecodeResults); + EXPECT_EQ(ARGO, irac._lastDecodeResults->decode_type); + std::ostringstream ossExpectedStr; + ossExpectedStr << "Config[CH#0]: Model: 2 (WREM3), Key: " << settingId + << ", Value: " << settingValue; + EXPECT_EQ(ossExpectedStr.str(), + IRAcUtils::resultAcToString(irac._lastDecodeResults.get())); + + stdAc::state_t r = {}; + ASSERT_TRUE(IRAcUtils::decodeToState(irac._lastDecodeResults.get(), &r, + nullptr)); + EXPECT_EQ(ARGO, r.protocol); + EXPECT_EQ(state.model, r.model); + EXPECT_EQ(state.command, r.command); +} + +INSTANTIATE_TEST_CASE_P( + TestIrAc, + TestArgoConfigViaIRAc_Positive, + ::testing::Values( + std::make_tuple(5, 0), + std::make_tuple(5, 1), + std::make_tuple(6, 0), + std::make_tuple(6, 1), + std::make_tuple(6, 2), + std::make_tuple(6, 3), + std::make_tuple(12, 30), + std::make_tuple(12, 75), + std::make_tuple(12, 99) +)); + +class TestArgoConfigViaIRAc_Negative : public TestArgoConfigViaIRAc {}; +TEST_P(TestArgoConfigViaIRAc_Negative, + ArgoWrem3_SyntheticSendAndDecode_Config_Negative) { + int16_t settingId = std::get<0>(GetParam()); + int16_t settingValue = std::get<1>(GetParam()); + IRac irac(kGpioUnused); + auto capture = std::make_shared(kGpioUnused); + irac._utReceiver = capture; + + stdAc::state_t state = {}; + state.protocol = ARGO; + state.model = argo_ac_remote_model_t::SAC_WREM3; + state.command = stdAc::ac_command_t::kConfigCommand; + state.clock = settingId; + state.sleep = settingValue; + + irac.sendAc(state, nullptr); + + // The "safe" mode should have prevented the message from sending out + ASSERT_EQ(nullptr, irac._lastDecodeResults); // nothing got sent +} + +INSTANTIATE_TEST_CASE_P( + TestIrAc, + TestArgoConfigViaIRAc_Negative, + ::testing::Values( + std::make_tuple(5, 2), + std::make_tuple(6, 4), + std::make_tuple(12, 29), + std::make_tuple(12, 100), + std::make_tuple(0, 0), + std::make_tuple(80, 86) +)); + + /******************************************************************************/ /* Tests for IRArgoACBase (comon functionality across WREM2 and WREM3) */ /******************************************************************************/ @@ -1296,6 +1453,7 @@ TEST(TestDecodeArgo, RealShortDecode) { stdAc::state_t r, p; // These short messages do result in a valid state (w/ room temperature only) EXPECT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); + EXPECT_EQ(stdAc::ac_command_t::kSensorTempReport, r.command); } ///