Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIDEA: Add support for Quiet, Clean & Freeze Protect controls. #1734

Merged
merged 4 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1502,16 +1502,21 @@ void IRac::lg(IRLgAc *ac, const lg_ac_remote_model_t model,
/// @param[in] degrees The temperature setting in degrees.
/// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting.
/// @param[in] quiet Run the device in quiet/silent mode.
/// @param[in] quiet_prev The device's previous quiet/silent mode.
/// @param[in] turbo Toggle the device's turbo/powerful mode.
/// @param[in] econo Toggle the device's economical mode.
/// @param[in] light Toggle the LED/Display mode.
/// @param[in] clean Turn on the self-cleaning mode. e.g. XFan, dry filters etc
/// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on.
/// @note On Danby A/C units, swingv controls the Ion Filter instead.
void IRac::midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool turbo,
const bool econo, const bool light, const int16_t sleep) {
const stdAc::swingv_t swingv,
const bool quiet, const bool quiet_prev,
const bool turbo, const bool econo, const bool light,
const bool clean, const int16_t sleep) {
ac->begin();
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
Expand All @@ -1520,12 +1525,12 @@ void IRac::midea(IRMideaAC *ac,
ac->setFan(ac->convertFan(fan));
ac->setSwingVToggle(swingv != stdAc::swingv_t::kOff);
// No Horizontal swing setting available.
// No Quiet setting available.
ac->setQuiet(quiet, quiet_prev);
ac->setTurboToggle(turbo);
ac->setEconoToggle(econo);
ac->setLightToggle(light);
// No Filter setting available.
// No Clean setting available.
ac->setCleanToggle(clean);
// No Beep setting available.
ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
// No Clock setting available.
Expand Down Expand Up @@ -2530,6 +2535,7 @@ stdAc::state_t IRac::handleToggles(const stdAc::state_t desired,
result.turbo = desired.turbo ^ prev->turbo;
result.econo = desired.econo ^ prev->econo;
result.light = desired.light ^ prev->light;
result.clean = desired.clean ^ prev->clean;
// FALL THRU
case decode_type_t::CORONA_AC:
case decode_type_t::HITACHI_AC344:
Expand Down Expand Up @@ -2645,6 +2651,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
const stdAc::swingv_t prev_swingv = (prev != NULL) ? prev->swingv
: stdAc::swingv_t::kOff;
#endif // (SEND_LG || SEND_SHARP_AC)
#if SEND_MIDEA
const bool prev_quiet = (prev != NULL) ? prev->quiet : !send.quiet;
#endif // SEND_MIDEA
// Per vendor settings & setup.
switch (send.protocol) {
#if SEND_AIRTON
Expand Down Expand Up @@ -2945,8 +2954,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
{
IRMideaAC ac(_pin, _inverted, _modulation);
midea(&ac, send.power, send.mode, send.celsius, send.degrees,
send.fanspeed, send.swingv, send.turbo, send.econo, send.light,
send.sleep);
send.fanspeed, send.swingv, send.quiet, prev_quiet, send.turbo,
send.econo, send.light, send.sleep);
break;
}
#endif // SEND_MIDEA
Expand Down
6 changes: 4 additions & 2 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,10 @@ void electra(IRElectraAc *ac,
void midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool turbo, const bool econo,
const bool light, const int16_t sleep = -1);
const stdAc::swingv_t swingv,
const bool quiet, const bool quiet_prev, const bool turbo,
const bool econo, const bool light, const bool clean,
const int16_t sleep = -1);
#endif // SEND_MIDEA
#if SEND_MIRAGE
void mirage(IRMirageAc *ac, const stdAc::state_t state);
Expand Down
107 changes: 98 additions & 9 deletions src/ir_Midea.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ using irutils::addIntToString;
using irutils::addLabeledString;
using irutils::addModeToString;
using irutils::addTempToString;
using irutils::addToggleToString;
using irutils::minsToString;

#if SEND_MIDEA
Expand Down Expand Up @@ -100,10 +101,13 @@ IRMideaAC::IRMideaAC(const uint16_t pin, const bool inverted,
void IRMideaAC::stateReset(void) {
// Power On, Mode Auto, Fan Auto, Temp = 25C/77F
_.remote_state = 0xA1826FFFFF62;
_SwingVToggle = false;
_CleanToggle = false;
_EconoToggle = false;
_TurboToggle = false;
_8CHeatToggle = false;
_LightToggle = false;
_Quiet = _Quiet_prev = false;
_SwingVToggle = false;
_TurboToggle = false;
#if KAYSUN_AC
_SwingVStep = false;
#endif // KAYSUN_AC
Expand Down Expand Up @@ -135,6 +139,19 @@ void IRMideaAC::send(const uint16_t repeat) {
if (_LightToggle && !isLightToggle())
_irsend.sendMidea(kMideaACToggleLight, kMideaBits, repeat);
_LightToggle = false;
if (getMode() <= kMideaACAuto) { // Only available in Cool, Dry, or Auto mode
if (_CleanToggle && !isCleanToggle())
_irsend.sendMidea(kMideaACToggleSelfClean, kMideaBits, repeat);
_CleanToggle = false;
} else if (getMode() == kMideaACHeat) { // Only available in Heat mode
if (_8CHeatToggle && !is8CHeatToggle())
_irsend.sendMidea(kMideaACToggle8CHeat, kMideaBits, repeat);
_8CHeatToggle = false;
}
if (_Quiet != _Quiet_prev)
_irsend.sendMidea(_Quiet ? kMideaACQuietOn : kMideaACQuietOff,
kMideaBits, repeat);
_Quiet_prev = _Quiet;
}
#endif // SEND_MIDEA

Expand Down Expand Up @@ -410,6 +427,75 @@ bool IRMideaAC::getLightToggle(void) {
return _LightToggle;
}

/// Is the current state a Self-Clean toggle message?
/// @return true, it is. false, it isn't.
bool IRMideaAC::isCleanToggle(void) const {
return _.remote_state == kMideaACToggleSelfClean;
}

/// Set the A/C to toggle the Self Clean mode for the next send.
/// @note Only works in Cool, Dry, or Auto modes.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRMideaAC::setCleanToggle(const bool on) {
_CleanToggle = on && getMode() <= kMideaACAuto;
}

// Get the Self-Clean toggle state of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRMideaAC::getCleanToggle(void) {
_CleanToggle |= isCleanToggle();
return _CleanToggle;
}

/// Is the current state a 8C Heat (Freeze Protect) toggle message?
/// @note Only works in Heat mode.
/// @return true, it is. false, it isn't.
bool IRMideaAC::is8CHeatToggle(void) const {
return _.remote_state == kMideaACToggle8CHeat;
}

/// Set the A/C to toggle the 8C Heat (Freeze Protect) mode for the next send.
/// @note Only works in Heat mode.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRMideaAC::set8CHeatToggle(const bool on) {
_8CHeatToggle = on && getMode() == kMideaACHeat;
}

// Get the 8C Heat (Freeze Protect) toggle state of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRMideaAC::get8CHeatToggle(void) {
_8CHeatToggle |= is8CHeatToggle();
return _8CHeatToggle;
}

/// Is the current state a Quiet(Silent) message?
/// @return true, it is. false, it isn't.
bool IRMideaAC::isQuiet(void) const {
return (_.remote_state == kMideaACQuietOff ||
_.remote_state == kMideaACQuietOn);
}

/// Set the Quiet (Silent) mode for the next send.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRMideaAC::setQuiet(const bool on) { _Quiet = on; }

/// Set the Quiet (Silent) mode for the next send.
/// @param[in] on true, the setting is on. false, the setting is off.
/// @param[in] prev true, previously the setting was on. false, setting was off.
void IRMideaAC::setQuiet(const bool on, const bool prev) {
setQuiet(on);
_Quiet_prev = prev;
}

// Get the Quiet (Silent) mode state of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRMideaAC::getQuiet(void) const {
if (isQuiet())
return _.remote_state == kMideaACQuietOn;
else
return _Quiet;
}

/// Calculate the checksum for a given state.
/// @param[in] state The value to calc the checksum of.
/// @return The calculated checksum value.
Expand Down Expand Up @@ -566,7 +652,7 @@ stdAc::fanspeed_t IRMideaAC::toCommonFanSpeed(const uint8_t speed) {
/// @param[in] prev A Ptr to the previous state.
/// @return The stdAc equivalent of the native settings.
stdAc::state_t IRMideaAC::toCommon(const stdAc::state_t *prev) {
stdAc::state_t result;
stdAc::state_t result{};
if (prev != NULL) {
result = *prev;
} else {
Expand All @@ -577,7 +663,6 @@ stdAc::state_t IRMideaAC::toCommon(const stdAc::state_t *prev) {
result.swingv = stdAc::swingv_t::kOff;
result.quiet = false;
result.turbo = false;
result.clean = false;
result.econo = false;
result.filter = false;
result.light = false;
Expand All @@ -597,6 +682,7 @@ stdAc::state_t IRMideaAC::toCommon(const stdAc::state_t *prev) {
result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = _.Sleep ? 0 : -1;
result.econo = getEconoToggle();
result.clean ^= getCleanToggle();
return result;
}

Expand All @@ -612,7 +698,7 @@ String IRMideaAC::toString(void) {
case kMideaACTypeCommand: result += kCommandStr; break;
case kMideaACTypeSpecial: result += kSpecialStr; break;
case kMideaACTypeFollow: result += kFollowStr; break;
default: result += kUnknownStr;
default: result += kUnknownStr;
}
result += ')';
if (message_type != kMideaACTypeSpecial) {
Expand Down Expand Up @@ -643,13 +729,16 @@ String IRMideaAC::toString(void) {
kMideaACFanAuto, kMideaACFanAuto, kMideaACFanMed);
result += addBoolToString(_.Sleep, kSleepStr);
}
result += addBoolToString(getSwingVToggle(), kSwingVToggleStr);
result += addToggleToString(getSwingVToggle(), kSwingVStr);
#if KAYSUN_AC
result += addBoolToString(getSwingVStep(), kStepStr);
#endif // KAYSUN_AC
result += addBoolToString(getEconoToggle(), kEconoToggleStr);
result += addBoolToString(getTurboToggle(), kTurboToggleStr);
result += addBoolToString(getLightToggle(), kLightToggleStr);
result += addToggleToString(getEconoToggle(), kEconoStr);
result += addToggleToString(getTurboToggle(), kTurboStr);
result += addBoolToString(getQuiet(), kQuietStr);
result += addToggleToString(getLightToggle(), kLightStr);
result += addToggleToString(getCleanToggle(), kCleanStr);
result += addToggleToString(get8CHeatToggle(), k8CHeatStr);
return result;
}

Expand Down
33 changes: 28 additions & 5 deletions src/ir_Midea.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// Brand: Danby, Model: R09C/BCGE remote (MIDEA)
// Brand: Trotec, Model: TROTEC PAC 3900 X (MIDEA)
// Brand: Trotec, Model: RG57H(B)/BGE remote (MIDEA)
// Brand: Lennox, Model: M0STAT60Q-1 remote (MIDEA)
crankyoldgit marked this conversation as resolved.
Show resolved Hide resolved
// Brand: Lennox, Model: RG57A6/BGEFU1 remote (MIDEA)

#ifndef IR_MIDEA_H_
#define IR_MIDEA_H_
Expand Down Expand Up @@ -123,9 +125,16 @@ const uint8_t kMideaACFanHigh = 3; // 0b11
// const uint64_t kMideaACToggleIonizer = 0xA201FFFFFF7C;
kSwingVToggleStr = kIonStr;
#endif // DANBY_DAC
const uint64_t kMideaACToggleEcono = 0xA202FFFFFF7E;
const uint64_t kMideaACToggleLight = 0xA208FFFFFF75;
const uint64_t kMideaACToggleTurbo = 0xA209FFFFFF74;
const uint64_t kMideaACToggleEcono = 0xA202FFFFFF7E;
const uint64_t kMideaACToggleLight = 0xA208FFFFFF75;
const uint64_t kMideaACToggleTurbo = 0xA209FFFFFF74;
// Mode must be Auto, Cool, or Dry
const uint64_t kMideaACToggleSelfClean = 0xA20DFFFFFF70;
// 8C Heat AKA Freeze Protection
const uint64_t kMideaACToggle8CHeat = 0xA20FFFFFFF73; // Only in Heat
const uint64_t kMideaACQuietOn = 0xA212FFFFFF6E;
const uint64_t kMideaACQuietOff = 0xA213FFFFFF6F;

const uint8_t kMideaACTypeCommand = 0b001; ///< Message type
const uint8_t kMideaACTypeSpecial = 0b010; ///< Message type
const uint8_t kMideaACTypeFollow = 0b100; ///< Message type
Expand Down Expand Up @@ -202,6 +211,16 @@ class IRMideaAC {
bool isLightToggle(void) const;
void setLightToggle(const bool on);
bool getLightToggle(void);
bool isCleanToggle(void) const;
void setCleanToggle(const bool on);
bool getCleanToggle(void);
bool is8CHeatToggle(void) const;
void set8CHeatToggle(const bool on);
bool get8CHeatToggle(void);
bool isQuiet(void) const;
void setQuiet(const bool on);
void setQuiet(const bool on, const bool prev);
bool getQuiet(void) const;
uint8_t getType(void) const;
bool isOnTimerEnabled(void) const;
uint16_t getOnTimer(void) const;
Expand All @@ -225,13 +244,17 @@ class IRMideaAC {
/// @endcond
#endif // UNIT_TEST
MideaProtocol _;
bool _CleanToggle;
bool _EconoToggle;
bool _8CHeatToggle;
bool _LightToggle;
bool _Quiet;
bool _Quiet_prev;
bool _SwingVToggle;
#if KAYSUN_AC
bool _SwingVStep;
#endif // KAYSUN_AC
bool _EconoToggle;
bool _TurboToggle;
bool _LightToggle;
void checksum(void);
static uint8_t calcChecksum(const uint64_t state);
void setType(const uint8_t type);
Expand Down
7 changes: 5 additions & 2 deletions test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1359,8 +1359,8 @@ TEST(TestIRac, Midea) {
char expected[] =
"Type: 1 (Command), Power: On, Mode: 1 (Dry), Celsius: On, "
"Temp: 27C/80F, On Timer: Off, Off Timer: Off, Fan: 2 (Medium), "
"Sleep: On, Swing(V) Toggle: Off, Econo Toggle: Off, "
"Turbo Toggle: Off, Light Toggle: Off";
"Sleep: On, Swing(V): -, Econo: -, "
"Turbo: -, Quiet: Off, Light: -, Clean: -, 8C Heat: -";

ac.begin();
irac.midea(&ac,
Expand All @@ -1370,9 +1370,12 @@ TEST(TestIRac, Midea) {
27, // Degrees
stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kOff, // Swing(V)
false, // Silent/Quiet
false, // Previous Silent/Quiet setting
false, // Turbo
false, // Econo
false, // Light
false, // Clean
8 * 60 + 0); // Sleep time

ASSERT_EQ(expected, ac.toString());
Expand Down
Loading