Skip to content

Commit

Permalink
SamsungAc: Add support for Horizontal Swing & Econo (#1667)
Browse files Browse the repository at this point in the history
* Update swing functions to work with both vertical & horizontal.
* Add Econo setting control.
* Add extra bit related to sleep timer mode.
* Extend & update unit tests.
* Remove old/redundant TODOs.
* Move some internal constants to the .cpp file.
* Bump string allocation in `toString()`.

For #1277 (comment)
  • Loading branch information
crankyoldgit authored Nov 10, 2021
1 parent 1c50b69 commit 817517c
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 118 deletions.
19 changes: 12 additions & 7 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1816,8 +1816,10 @@ void IRac::panasonic32(IRPanasonicAc32 *ac,
/// @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] swingh The horizontal swing setting.
/// @param[in] quiet Run the device in quiet/silent mode.
/// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] econo Run the device in economical mode.
/// @param[in] light Turn on the LED/Display mode.
/// @param[in] filter Turn on the (ion/pollen/etc) filter mode.
/// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc
Expand All @@ -1829,8 +1831,10 @@ void IRac::panasonic32(IRPanasonicAc32 *ac,
void IRac::samsung(IRSamsungAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool quiet, const bool turbo, const bool light,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool econo,
const bool light,
const bool filter, const bool clean,
const bool beep, const int16_t sleep,
const bool prevpower, const int16_t prevsleep,
Expand All @@ -1842,11 +1846,11 @@ void IRac::samsung(IRSamsungAc *ac,
ac->setTemp(degrees);
ac->setFan(ac->convertFan(fan));
ac->setSwing(swingv != stdAc::swingv_t::kOff);
// No Horizontal swing setting available.
ac->setSwingH(swingh != stdAc::swingh_t::kOff);
ac->setQuiet(quiet);
ac->setPowerful(turbo);
ac->setPowerful(turbo); // FYI, `setEcono(true)` will override this.
ac->setDisplay(light);
// No Econo setting available.
ac->setEcono(econo);
ac->setIon(filter);
ac->setClean(clean);
ac->setBeep(beep);
Expand Down Expand Up @@ -2981,8 +2985,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
{
IRSamsungAc ac(_pin, _inverted, _modulation);
samsung(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.quiet, send.turbo, send.light, send.filter, send.clean,
send.beep, send.sleep, prev_power, prev_sleep);
send.swingh, send.quiet, send.turbo, send.econo, send.light,
send.filter, send.clean, send.beep, send.sleep,
prev_power, prev_sleep);
break;
}
#endif // SEND_SAMSUNG_AC
Expand Down
7 changes: 4 additions & 3 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,10 @@ void electra(IRElectraAc *ac,
#if SEND_SAMSUNG_AC
void samsung(IRSamsungAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool quiet, const bool turbo, const bool light,
const bool filter, const bool clean,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool econo,
const bool light, const bool filter, const bool clean,
const bool beep, const int16_t sleep = -1,
const bool prevpower = true, const int16_t prevsleep = -1,
const bool forceextended = true);
Expand Down
103 changes: 86 additions & 17 deletions src/ir_Samsung.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017, 2018, 2019 David Conran
// Copyright 2017-2021 David Conran
/// @file
/// @brief Support for Samsung protocols.
/// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/
Expand Down Expand Up @@ -62,6 +62,17 @@ const uint16_t kSamsung36BitMark = 512; /// < uSeconds
const uint16_t kSamsung36OneSpace = 1468; /// < uSeconds
const uint16_t kSamsung36ZeroSpace = 490; /// < uSeconds

// _.Swing
const uint8_t kSamsungAcSwingV = 0b010;
const uint8_t kSamsungAcSwingH = 0b011;
const uint8_t kSamsungAcSwingBoth = 0b100;
const uint8_t kSamsungAcSwingOff = 0b111;
// _.FanSpecial
const uint8_t kSamsungAcFanSpecialOff = 0b000;
const uint8_t kSamsungAcPowerfulOn = 0b011;
const uint8_t kSamsungAcBreezeOn = 0b101;
const uint8_t kSamsungAcEconoOn = 0b111;

using irutils::addBoolToString;
using irutils::addFanToString;
using irutils::addIntToString;
Expand Down Expand Up @@ -443,7 +454,7 @@ void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) {
if (length > kSamsungAcStateLength) {
_OnTimerEnable = _.OnTimerEnable;
_OffTimerEnable = _.OffTimerEnable;
_Sleep = _.Sleep;
_Sleep = _.Sleep5 && _.Sleep12;
_OnTimer = _getOnTimer();
_OffTimer = _getOffTimer();
for (uint8_t i = kSamsungAcStateLength; i < length; i++)
Expand Down Expand Up @@ -535,18 +546,48 @@ uint8_t IRSamsungAc::getFan(void) const {

/// Get the vertical swing setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
/// @todo (Hollako) Explain why sometimes the LSB of remote_state[9] is a 1.
/// e.g. 0xAE or 0XAF for swing move.
bool IRSamsungAc::getSwing(void) const {
return _.Swing == kSamsungAcSwingMove;
switch (_.Swing) {
case kSamsungAcSwingV:
case kSamsungAcSwingBoth: return true;
default: return false;
}
}

/// Set the vertical swing setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
/// @todo (Hollako) Explain why sometimes the LSB of remote_state[9] is a 1.
/// e.g. 0xAE or 0XAF for swing move.
void IRSamsungAc::setSwing(const bool on) {
_.Swing = (on ? kSamsungAcSwingMove : kSamsungAcSwingStop);
switch (_.Swing) {
case kSamsungAcSwingBoth:
case kSamsungAcSwingH:
_.Swing = on ? kSamsungAcSwingBoth : kSamsungAcSwingH;
break;
default:
_.Swing = on ? kSamsungAcSwingV : kSamsungAcSwingOff;
}
}

/// Get the horizontal swing setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRSamsungAc::getSwingH(void) const {
switch (_.Swing) {
case kSamsungAcSwingH:
case kSamsungAcSwingBoth: return true;
default: return false;
}
}

/// Set the horizontal swing setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRSamsungAc::setSwingH(const bool on) {
switch (_.Swing) {
case kSamsungAcSwingV:
case kSamsungAcSwingBoth:
_.Swing = on ? kSamsungAcSwingBoth : kSamsungAcSwingV;
break;
default:
_.Swing = on ? kSamsungAcSwingH : kSamsungAcSwingOff;
}
}

/// Get the Beep setting of the A/C.
Expand Down Expand Up @@ -599,7 +640,8 @@ bool IRSamsungAc::getPowerful(void) const {
/// Set the Powerful (Turbo) setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRSamsungAc::setPowerful(const bool on) {
uint8_t off_value = getBreeze() ? kSamsungAcBreezeOn : 0b000;
uint8_t off_value = (getBreeze() || getEcono()) ? _.FanSpecial
: kSamsungAcFanSpecialOff;
_.FanSpecial = (on ? kSamsungAcPowerfulOn : off_value);
if (on) {
// Powerful mode sets fan speed to Turbo.
Expand All @@ -623,14 +665,36 @@ bool IRSamsungAc::getBreeze(void) const {
/// @param[in] on true, the setting is on. false, the setting is off.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
void IRSamsungAc::setBreeze(const bool on) {
const uint8_t off_value = getPowerful() ? kSamsungAcPowerfulOn : 0b000;
const uint8_t off_value = (getPowerful() ||
getEcono()) ? _.FanSpecial
: kSamsungAcFanSpecialOff;
_.FanSpecial = (on ? kSamsungAcBreezeOn : off_value);
if (on) {
setFan(kSamsungAcFanAuto);
setSwing(false);
}
}

/// Get the current Economy (Eco) setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRSamsungAc::getEcono(void) const {
return (_.FanSpecial == kSamsungAcEconoOn) &&
(_.Fan == kSamsungAcFanAuto && getSwing());
}

/// Set the current Economy (Eco) setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRSamsungAc::setEcono(const bool on) {
const uint8_t off_value = (getBreeze() ||
getPowerful()) ? _.FanSpecial
: kSamsungAcFanSpecialOff;
_.FanSpecial = (on ? kSamsungAcEconoOn : off_value);
if (on) {
setFan(kSamsungAcFanAuto);
setSwing(true);
}
}

/// Get the Display (Light/LED) setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRSamsungAc::getDisplay(void) const { return _.Display; }
Expand Down Expand Up @@ -693,7 +757,8 @@ void IRSamsungAc::_setOffTimer(void) {
void IRSamsungAc::_setSleepTimer(void) {
_setOffTimer();
// The Sleep mode/timer should only be engaged if an off time has been set.
_.Sleep = _Sleep && _OffTimerEnable;
_.Sleep5 = _Sleep && _OffTimerEnable;
_.Sleep12 = _.Sleep5;
}

/// Get the On Timer setting of the A/C.
Expand Down Expand Up @@ -724,6 +789,7 @@ uint16_t IRSamsungAc::getSleepTimer(void) const {
void IRSamsungAc::setOnTimer(const uint16_t nr_of_mins) {
// Limit to one day, and round down to nearest 10 min increment.
_OnTimer = TIMER_RESOLUTION(nr_of_mins);
_OnTimerEnable = _OnTimer > 0;
if (_OnTimer) _Sleep = false;
}

Expand All @@ -734,6 +800,7 @@ void IRSamsungAc::setOnTimer(const uint16_t nr_of_mins) {
void IRSamsungAc::setOffTimer(const uint16_t nr_of_mins) {
// Limit to one day, and round down to nearest 10 min increment.
_OffTimer = TIMER_RESOLUTION(nr_of_mins);
_OffTimerEnable = _OffTimer > 0;
if (_OffTimer) _Sleep = false;
}

Expand All @@ -746,6 +813,7 @@ void IRSamsungAc::setSleepTimer(const uint16_t nr_of_mins) {
_OffTimer = TIMER_RESOLUTION(nr_of_mins);
if (_OffTimer) setOnTimer(0); // Clear the on timer if set.
_Sleep = _OffTimer > 0;
_OffTimerEnable = _Sleep;
}

/// Convert a stdAc::opmode_t enum into its native mode.
Expand Down Expand Up @@ -812,18 +880,17 @@ stdAc::state_t IRSamsungAc::toCommon(void) const {
result.celsius = true;
result.degrees = getTemp();
result.fanspeed = toCommonFanSpeed(_.Fan);
result.swingv = getSwing() ? stdAc::swingv_t::kAuto :
stdAc::swingv_t::kOff;
result.swingv = getSwing() ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff;
result.quiet = getQuiet();
result.turbo = getPowerful();
result.econo = getEcono();
result.clean = getClean();
result.beep = _.Beep;
result.light = _.Display;
result.filter = _.Ion;
result.sleep = _Sleep ? getSleepTimer() : -1;
// Not supported.
result.swingh = stdAc::swingh_t::kOff;
result.econo = false;
result.clock = -1;
return result;
}
Expand All @@ -832,7 +899,7 @@ stdAc::state_t IRSamsungAc::toCommon(void) const {
/// @return A human readable string.
String IRSamsungAc::toString(void) const {
String result = "";
result.reserve(115); // Reserve some heap for the string to reduce fragging.
result.reserve(230); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), kPowerStr, false);
result += addModeToString(_.Mode, kSamsungAcAuto, kSamsungAcCool,
kSamsungAcHeat, kSamsungAcDry,
Expand Down Expand Up @@ -862,11 +929,13 @@ String IRSamsungAc::toString(void) const {
break;
}
result += ')';
result += addBoolToString(getSwing(), kSwingStr);
result += addBoolToString(getSwing(), kSwingVStr);
result += addBoolToString(getSwingH(), kSwingHStr);
result += addBoolToString(_.Beep, kBeepStr);
result += addBoolToString(getClean(), kCleanStr);
result += addBoolToString(getQuiet(), kQuietStr);
result += addBoolToString(getPowerful(), kPowerfulStr);
result += addBoolToString(getEcono(), kEconoStr);
result += addBoolToString(getBreeze(), kBreezeStr);
result += addBoolToString(_.Display, kLightStr);
result += addBoolToString(_.Ion, kIonStr);
Expand Down
17 changes: 9 additions & 8 deletions src/ir_Samsung.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 David Conran
// Copyright 2018-2021 David Conran
/// @file
/// @brief Support for Samsung protocols.
/// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/
Expand Down Expand Up @@ -58,7 +58,8 @@ union SamsungProtocol{
// Byte 4
uint8_t :8;
// Byte 5
uint8_t :5;
uint8_t :4;
uint8_t Sleep5 :1;
uint8_t Quiet :1;
uint8_t :2;
// Byte 6
Expand All @@ -76,7 +77,7 @@ union SamsungProtocol{
uint8_t :1;
// Byte 10
uint8_t :1;
uint8_t FanSpecial :3; // Powerful, Breeze/WindFree
uint8_t FanSpecial :3; // Powerful, Breeze/WindFree, Econo
uint8_t Display :1;
uint8_t :2;
uint8_t Clean10 :1;
Expand Down Expand Up @@ -136,7 +137,7 @@ union SamsungProtocol{
uint8_t OffTimeDay :1;
uint8_t OnTimerEnable :1;
uint8_t OffTimerEnable :1;
uint8_t Sleep :1;
uint8_t Sleep12 :1;
uint8_t OnTimeDay :1;
uint8_t :3;
// Byte 13
Expand All @@ -162,10 +163,6 @@ union SamsungProtocol{
};

// Constants
const uint8_t kSamsungAcSwingMove = 0b010;
const uint8_t kSamsungAcSwingStop = 0b111;
const uint8_t kSamsungAcPowerfulOn = 0b011;
const uint8_t kSamsungAcBreezeOn = 0b101;
const uint8_t kSamsungAcMinTemp = 16; // C Mask 0b11110000
const uint8_t kSamsungAcMaxTemp = 30; // C Mask 0b11110000
const uint8_t kSamsungAcAutoTemp = 25; // C Mask 0b11110000
Expand Down Expand Up @@ -214,6 +211,8 @@ class IRSamsungAc {
uint8_t getMode(void) const;
void setSwing(const bool on);
bool getSwing(void) const;
void setSwingH(const bool on);
bool getSwingH(void) const;
void setBeep(const bool on);
bool getBeep(void) const;
void setClean(const bool on);
Expand All @@ -224,6 +223,8 @@ class IRSamsungAc {
bool getPowerful(void) const;
void setBreeze(const bool on);
bool getBreeze(void) const;
void setEcono(const bool on);
bool getEcono(void) const;
void setDisplay(const bool on);
bool getDisplay(void) const;
void setIon(const bool on);
Expand Down
Loading

0 comments on commit 817517c

Please sign in to comment.