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

SharpAc: Allow position control of SwingV #1594

Merged
merged 4 commits into from
Sep 6, 2021
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
16 changes: 9 additions & 7 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,7 @@ void IRac::sanyo88(IRSanyoAc88 *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] swingv_prev The previous vertical swing setting.
/// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] light Turn on the LED/Display mode.
/// @param[in] filter Turn on the (ion/pollen/etc) filter mode.
Expand All @@ -1901,14 +1902,15 @@ void IRac::sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model,
const bool on, const bool prev_power,
const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool turbo,
const stdAc::swingv_t swingv,
const stdAc::swingv_t swingv_prev, const bool turbo,
const bool light, const bool filter, const bool clean) {
ac->begin();
ac->setModel(model);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
ac->setFan(ac->convertFan(fan, model));
ac->setSwingToggle(swingv != stdAc::swingv_t::kOff);
if (swingv != swingv_prev) ac->setSwingV(ac->convertSwingV(swingv));
// Econo deliberately not used as it cycles through 3 modes uncontrollably.
// ac->setEconoToggle(econo);
ac->setIon(filter);
Expand Down Expand Up @@ -2495,10 +2497,10 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
#if (SEND_HITACHI_AC1 || SEND_SAMSUNG_AC || SEND_SHARP_AC)
const bool prev_power = (prev != NULL) ? prev->power : !send.power;
#endif // (SEND_HITACHI_AC1 || SEND_SAMSUNG_AC || SEND_SHARP_AC)
#if SEND_LG
#if (SEND_LG || SEND_SHARP_AC)
const stdAc::swingv_t prev_swingv = (prev != NULL) ? prev->swingv
: stdAc::swingv_t::kOff;
#endif // SEND_LG
#endif // (SEND_LG || SEND_SHARP_AC)
// Per vendor settings & setup.
switch (send.protocol) {
#if SEND_AIRWELL
Expand Down Expand Up @@ -2899,8 +2901,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
{
IRSharpAc ac(_pin, _inverted, _modulation);
sharp(&ac, (sharp_ac_remote_model_t)send.model, send.power, prev_power,
send.mode, degC, send.fanspeed, send.swingv, send.turbo, send.light,
send.filter, send.clean);
send.mode, degC, send.fanspeed, send.swingv, prev_swingv,
send.turbo, send.light, send.filter, send.clean);
break;
}
#endif // SEND_SHARP_AC
Expand Down Expand Up @@ -4136,7 +4138,7 @@ namespace IRAcUtils {
case decode_type_t::SHARP_AC: {
IRSharpAc ac(kGpioUnused);
ac.setRaw(decode->state);
*result = ac.toCommon();
*result = ac.toCommon(prev);
break;
}
#endif // DECODE_SHARP_AC
Expand Down
3 changes: 2 additions & 1 deletion src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,8 @@ void electra(IRElectraAc *ac,
void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model,
const bool on, const bool prev_power, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool turbo, const bool light,
const stdAc::swingv_t swingv, const stdAc::swingv_t swingv_prev,
const bool turbo, const bool light,
const bool filter, const bool clean);
#endif // SEND_SHARP_AC
#if SEND_TCL112AC
Expand Down
122 changes: 105 additions & 17 deletions src/ir_Sharp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ using irutils::addIntToString;
using irutils::addLabeledString;
using irutils::addModeToString;
using irutils::addModelToString;
using irutils::addSwingVToString;
using irutils::addTempToString;
using irutils::minsToString;

Expand Down Expand Up @@ -544,24 +545,69 @@ void IRSharpAc::setTurbo(const bool on) {
_.Special = kSharpAcSpecialTurbo;
}

/// Get the Vertical Swing setting of the A/C.
/// @return The position of the Vertical Swing setting.
uint8_t IRSharpAc::getSwingV(void) const { return _.Swing; }

/// Set the Vertical Swing setting of the A/C.
/// @note Some positions may not work on all models.
/// @param[in] position The desired position/setting.
/// @param[in] force Do we override the safety checks and just do it?
void IRSharpAc::setSwingV(const uint8_t position, const bool force) {
switch (position) {
case kSharpAcSwingVCoanda:
// Only allowed in Heat mode.
if (!force && getMode() != kSharpAcHeat) {
setSwingV(kSharpAcSwingVLow); // Use the next lowest setting.
return;
}
// FALLTHRU
case kSharpAcSwingVHigh:
case kSharpAcSwingVMid:
case kSharpAcSwingVLow:
case kSharpAcSwingVToggle:
case kSharpAcSwingVOff:
case kSharpAcSwingVLast: // Technically valid, but we don't use it.
// All expected non-positions set the special bits.
_.Special = kSharpAcSpecialSwing;
// FALLTHRU
case kSharpAcSwingVIgnore:
_.Swing = position;
}
}

/// Convert a standard A/C vertical swing into its native setting.
/// @param[in] position A stdAc::swingv_t position to convert.
/// @return The equivalent native horizontal swing position.
uint8_t IRSharpAc::convertSwingV(const stdAc::swingv_t position) {
switch (position) {
case stdAc::swingv_t::kHighest:
case stdAc::swingv_t::kHigh: return kSharpAcSwingVHigh;
case stdAc::swingv_t::kMiddle: return kSharpAcSwingVMid;
case stdAc::swingv_t::kLow: return kSharpAcSwingVLow;
case stdAc::swingv_t::kLowest: return kSharpAcSwingVCoanda;
case stdAc::swingv_t::kAuto: return kSharpAcSwingVToggle;
case stdAc::swingv_t::kOff: return kSharpAcSwingVOff;
default: return kSharpAcSwingVIgnore;
}
}

/// Get the (vertical) Swing Toggle setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRSharpAc::getSwingToggle(void) const {
return _.Swing == kSharpAcSwingToggle;
return getSwingV() == kSharpAcSwingVToggle;
}

/// Set the (vertical) Swing Toggle setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRSharpAc::setSwingToggle(const bool on) {
_.Swing = (on ? kSharpAcSwingToggle : kSharpAcSwingNoToggle);
setSwingV(on ? kSharpAcSwingVToggle : kSharpAcSwingVIgnore);
if (on) _.Special = kSharpAcSpecialSwing;
}

/// Get the Ion (Filter) setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRSharpAc::getIon(void) const {
return _.Ion;
}
bool IRSharpAc::getIon(void) const { return _.Ion; }

/// Set the Ion (Filter) setting of the A/C.
/// @param[in] on true, the setting is on. false, the setting is off.
Expand Down Expand Up @@ -628,15 +674,11 @@ uint16_t IRSharpAc::getTimerTime(void) const {

/// Is the Timer enabled?
/// @return true, the setting is on. false, the setting is off.
bool IRSharpAc::getTimerEnabled(void) const {
return _.TimerEnabled;
}
bool IRSharpAc::getTimerEnabled(void) const { return _.TimerEnabled; }

/// Get the current timer type.
/// @return true, It's an "On" timer. false, It's an "Off" timer.
bool IRSharpAc::getTimerType(void) const {
return _.TimerType;
}
bool IRSharpAc::getTimerType(void) const { return _.TimerType; }

/// Set or cancel the timer function.
/// @param[in] enable Is the timer to be enabled (true) or canceled(false)?
Expand Down Expand Up @@ -765,10 +807,34 @@ stdAc::fanspeed_t IRSharpAc::toCommonFanSpeed(const uint8_t speed) const {
}
}

/// Convert a native vertical swing postion to it's common equivalent.
/// @param[in] pos A native position to convert.
/// @param[in] mode What operating mode are we in?
/// @return The common vertical swing position.
stdAc::swingv_t IRSharpAc::toCommonSwingV(const uint8_t pos,
const stdAc::opmode_t mode) const {
switch (pos) {
case kSharpAcSwingVHigh: return stdAc::swingv_t::kHighest;
case kSharpAcSwingVMid: return stdAc::swingv_t::kMiddle;
case kSharpAcSwingVLow: return stdAc::swingv_t::kLow;
case kSharpAcSwingVCoanda: // Coanda has mode dependent positionss
switch (mode) {
case stdAc::opmode_t::kCool: return stdAc::swingv_t::kHighest;
case stdAc::opmode_t::kHeat: return stdAc::swingv_t::kLowest;
default: return stdAc::swingv_t::kOff;
}
case kSharpAcSwingVToggle: return stdAc::swingv_t::kAuto;
default: return stdAc::swingv_t::kOff;
}
}

/// Convert the current internal state into its stdAc::state_t equivalent.
/// @param[in] prev Ptr to the previous state if required.
/// @return The stdAc equivalent of the native settings.
stdAc::state_t IRSharpAc::toCommon(void) const {
stdAc::state_t IRSharpAc::toCommon(const stdAc::state_t *prev) const {
stdAc::state_t result;
// Start with the previous state if given it.
if (prev != NULL) result = *prev;
result.protocol = decode_type_t::SHARP_AC;
result.model = getModel();
result.power = getPower();
Expand All @@ -777,8 +843,8 @@ stdAc::state_t IRSharpAc::toCommon(void) const {
result.degrees = getTemp();
result.fanspeed = toCommonFanSpeed(_.Fan);
result.turbo = getTurbo();
result.swingv = getSwingToggle() ? stdAc::swingv_t::kAuto
: stdAc::swingv_t::kOff;
if (getSwingV() != kSharpAcSwingVIgnore)
result.swingv = toCommonSwingV(getSwingV(), result.mode);
result.filter = _.Ion;
result.econo = getEconoToggle();
result.light = getLightToggle();
Expand All @@ -797,14 +863,15 @@ stdAc::state_t IRSharpAc::toCommon(void) const {
String IRSharpAc::toString(void) const {
String result = "";
const sharp_ac_remote_model_t model = getModel();
result.reserve(160); // Reserve some heap for the string to reduce fragging.
result.reserve(170); // Reserve some heap for the string to reduce fragging.
result += addModelToString(decode_type_t::SHARP_AC, getModel(), false);

result += addLabeledString(isPowerSpecial() ? "-"
: (getPower() ? kOnStr : kOffStr),
kPowerStr);
const uint8_t mode = _.Mode;
result += addModeToString(
_.Mode,
mode,
// Make the value invalid if the model doesn't support an Auto mode.
(model == sharp_ac_remote_model_t::A907) ? kSharpAcAuto : 255,
kSharpAcCool, kSharpAcHeat, kSharpAcDry, kSharpAcFan);
Expand All @@ -821,8 +888,29 @@ String IRSharpAc::toString(void) const {
kSharpAcFanAuto, kSharpAcFanAuto,
kSharpAcFanMed);
}
if (getSwingV() == kSharpAcSwingVIgnore) {
result += addIntToString(kSharpAcSwingVIgnore, kSwingVStr);
result += kSpaceLBraceStr;
result += kNAStr;
result += ')';
} else {
result += addSwingVToString(
getSwingV(), 0xFF,
// Coanda means Highest when in Cool mode.
(mode == kSharpAcCool) ? kSharpAcSwingVCoanda : kSharpAcSwingVToggle,
kSharpAcSwingVHigh,
0xFF, // Upper Middle is unused
kSharpAcSwingVMid,
0xFF, // Lower Middle is unused
kSharpAcSwingVLow,
kSharpAcSwingVCoanda,
kSharpAcSwingVOff,
// Below are unused.
kSharpAcSwingVToggle,
0xFF,
0xFF);
}
result += addBoolToString(getTurbo(), kTurboStr);
result += addBoolToString(getSwingToggle(), kSwingVToggleStr);
result += addBoolToString(_.Ion, kIonStr);
switch (model) {
case sharp_ac_remote_model_t::A705:
Expand Down
20 changes: 17 additions & 3 deletions src/ir_Sharp.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,16 @@ const uint8_t kSharpAcTimerHoursMax = 0b1100; // 12
const uint8_t kSharpAcOffTimerType = 0b0;
const uint8_t kSharpAcOnTimerType = 0b1;

const uint8_t kSharpAcSwingToggle = 0b111;
const uint8_t kSharpAcSwingNoToggle = 0b000;
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/discussions/1590#discussioncomment-1260213
const uint8_t kSharpAcSwingVIgnore = 0b000; // Don't change the swing setting.
const uint8_t kSharpAcSwingVHigh = 0b001; // 0° down aka Coanda (Cool)
const uint8_t kSharpAcSwingVOff = 0b010; // Stop & Go to last fixed pos.
const uint8_t kSharpAcSwingVMid = 0b011; // 30° down
const uint8_t kSharpAcSwingVLow = 0b100; // 45° down
const uint8_t kSharpAcSwingVLast = 0b101; // Same as kSharpAcSwingVOff.
const uint8_t kSharpAcSwingVCoanda = 0b110; // 0° down (Cool), 75° down (Heat)
const uint8_t kSharpAcSwingVLowest = kSharpAcSwingVCoanda;
const uint8_t kSharpAcSwingVToggle = 0b111; // Toggle Constant swinging on/off.

const uint8_t kSharpAcSpecialPower = 0x00;
const uint8_t kSharpAcSpecialTurbo = 0x01;
Expand Down Expand Up @@ -167,6 +175,8 @@ class IRSharpAc {
void setTurbo(const bool on);
bool getSwingToggle(void) const;
void setSwingToggle(const bool on);
uint8_t getSwingV(void) const;
void setSwingV(const uint8_t position, const bool force = false);
bool getIon(void) const;
void setIon(const bool on);
bool getEconoToggle(void) const;
Expand All @@ -188,9 +198,13 @@ class IRSharpAc {
static uint8_t convertFan(const stdAc::fanspeed_t speed,
const sharp_ac_remote_model_t model =
sharp_ac_remote_model_t::A907);
static uint8_t convertSwingV(const stdAc::swingv_t position);
stdAc::opmode_t toCommonMode(const uint8_t mode) const;
stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed) const;
stdAc::state_t toCommon(void) const;
stdAc::swingv_t toCommonSwingV(
const uint8_t pos,
const stdAc::opmode_t mode = stdAc::opmode_t::kHeat) const;
stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const;
String toString(void) const;
#ifndef UNIT_TEST

Expand Down
3 changes: 2 additions & 1 deletion test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,7 @@ TEST(TestIRac, Sharp) {
IRrecv capture(kGpioUnused);
char expected[] =
"Model: 1 (A907), Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), "
"Turbo: Off, Swing(V) Toggle: On, Ion: On, Econo: -, Clean: Off";
"Swing(V): 7 (Swing), Turbo: Off, Ion: On, Econo: -, Clean: Off";

ac.begin();
irac.sharp(&ac,
Expand All @@ -1621,6 +1621,7 @@ TEST(TestIRac, Sharp) {
28, // Celsius
stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kAuto, // Vertical swing
stdAc::swingv_t::kOff, // Previous Vertical swing
false, // Turbo
false, // Light
true, // Filter (Ion)
Expand Down
Loading