mirror of
https://github.com/crankyoldgit/IRremoteESP8266.git
synced 2026-01-12 00:05:10 +08:00
SharpAc: Allow position control of SwingV (#1594)
* Add the ability to set Vertical Swing positions via `setSwingV()`
- e.g. Coanda setting.
* Modify `setSwingV()` to take an optional parameter to override the heat mode check.
* Enable forcing of Coanda mode in Cool.
- Several other undocumented positions discovered via experimentation.
- May not work on all models.
* Update & add unit tests accordingly.
Fixes #1590
This commit is contained in:
16
src/IRac.cpp
16
src/IRac.cpp
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
126
src/ir_Sharp.cpp
126
src/ir_Sharp.cpp
@@ -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;
|
||||
|
||||
@@ -544,24 +545,73 @@ 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.
|
||||
/// @note `setSwingV(kSharpAcSwingVLowest)` will only allow the Lowest setting
|
||||
/// in Heat mode, it will default to `kSharpAcSwingVLow` otherwise.
|
||||
/// If you want to set this value in other modes e.g. Cool, you must
|
||||
/// use `setSwingV`s optional `force` parameter.
|
||||
/// @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.
|
||||
@@ -628,15 +678,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)?
|
||||
@@ -765,10 +811,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();
|
||||
@@ -777,8 +847,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();
|
||||
@@ -797,14 +867,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);
|
||||
@@ -821,8 +892,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:
|
||||
|
||||
@@ -122,8 +122,23 @@ 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. Similar to Cool Coanda.
|
||||
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.
|
||||
// Toggles between last fixed pos & either 75° down (Heat) or 0° down (Cool)
|
||||
// i.e. alternate between last pos <-> 75° down if in Heat mode, AND
|
||||
// alternate between last pos <-> 0° down if in Cool mode.
|
||||
// Note: `setSwingV(kSharpAcSwingVLowest)` will only allow the Lowest setting in
|
||||
// Heat mode, it will default to `kSharpAcSwingVLow` otherwise.
|
||||
// If you want to set this value in other modes e.g. Cool, you must
|
||||
// use `setSwingV`s optional `force` parameter.
|
||||
const uint8_t kSharpAcSwingVLowest = 0b110;
|
||||
const uint8_t kSharpAcSwingVCoanda = kSharpAcSwingVLowest;
|
||||
const uint8_t kSharpAcSwingVToggle = 0b111; // Toggle Constant swinging on/off.
|
||||
|
||||
const uint8_t kSharpAcSpecialPower = 0x00;
|
||||
const uint8_t kSharpAcSpecialTurbo = 0x01;
|
||||
@@ -167,6 +182,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;
|
||||
@@ -188,9 +205,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
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -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)
|
||||
|
||||
@@ -410,8 +410,8 @@ TEST(TestDecodeSharpAc, RealExample) {
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto), "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
@@ -561,7 +561,7 @@ TEST(TestSharpAcClass, OperatingMode) {
|
||||
// Check toString() says Fan rather than Auto.
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (A705), Power: Off, Mode: 0 (Fan), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@@ -615,8 +615,8 @@ TEST(TestSharpAcClass, ReconstructKnownState) {
|
||||
EXPECT_STATE_EQ(on_auto_auto, ac.getRaw(), kSharpAcBits);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
uint8_t cool_auto_28[kSharpAcStateLength] = {
|
||||
@@ -629,8 +629,8 @@ TEST(TestSharpAcClass, ReconstructKnownState) {
|
||||
ac.setTemp(28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
EXPECT_STATE_EQ(cool_auto_28, ac.getRaw(), kSharpAcBits);
|
||||
}
|
||||
@@ -647,8 +647,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(off_auto_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t on_auto_auto[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0,
|
||||
@@ -657,8 +657,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(on_auto_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_auto_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
|
||||
@@ -667,8 +667,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(cool_auto_28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan1_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x42, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
@@ -677,8 +677,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(cool_fan1_28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan2_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x32, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
@@ -688,7 +688,7 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan3_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x52, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
@@ -698,7 +698,7 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 5 (UNKNOWN), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan4_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x72, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
@@ -707,8 +707,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(cool_fan4_28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan4_28_ion_on[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x61, 0x72, 0x08, 0x08, 0x80, 0x00, 0xE4,
|
||||
@@ -717,8 +717,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(cool_fan4_28_ion_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Econo: -, Clean: Off",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: On, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
/* Unsupported / Not yet reverse engineered.
|
||||
uint8_t cool_fan4_28_eco1[kSharpAcStateLength] = {
|
||||
@@ -735,8 +735,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
||||
ac.setRaw(dry_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@@ -747,6 +747,7 @@ TEST(TestSharpAcClass, toCommon) {
|
||||
ac.setMode(kSharpAcCool);
|
||||
ac.setTemp(20);
|
||||
ac.setFan(kSharpAcFanMax);
|
||||
ac.setSwingV(kSharpAcSwingVOff);
|
||||
// Now test it.
|
||||
ASSERT_EQ(decode_type_t::SHARP_AC, ac.toCommon().protocol);
|
||||
ASSERT_TRUE(ac.toCommon().power);
|
||||
@@ -755,8 +756,8 @@ TEST(TestSharpAcClass, toCommon) {
|
||||
ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode);
|
||||
ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed);
|
||||
ASSERT_EQ(sharp_ac_remote_model_t::A705, ac.toCommon().model);
|
||||
// Unsupported.
|
||||
ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv);
|
||||
// Unsupported.
|
||||
ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh);
|
||||
ASSERT_FALSE(ac.toCommon().turbo);
|
||||
ASSERT_FALSE(ac.toCommon().quiet);
|
||||
@@ -868,20 +869,20 @@ TEST(TestSharpAcClass, Turbo) {
|
||||
EXPECT_EQ(kSharpAcFanMax, ac.getFan());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: On, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), "
|
||||
"Swing(V): 0 (N/A), Turbo: On, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
ac.setRaw(off_state);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestSharpAcClass, SwingToggle) {
|
||||
TEST(TestSharpAcClass, Swings) {
|
||||
IRSharpAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
@@ -906,6 +907,70 @@ TEST(TestSharpAcClass, SwingToggle) {
|
||||
|
||||
ac.setRaw(off_state);
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
// Vertical
|
||||
ac.setSwingV(kSharpAcSwingVToggle);
|
||||
EXPECT_EQ(kSharpAcSwingVToggle, ac.getSwingV());
|
||||
EXPECT_TRUE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVHigh);
|
||||
EXPECT_EQ(kSharpAcSwingVHigh, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(0xFF); // Doesn't change if invalid position given.
|
||||
EXPECT_EQ(kSharpAcSwingVHigh, ac.getSwingV());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVMid);
|
||||
EXPECT_EQ(kSharpAcSwingVMid, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVLow);
|
||||
EXPECT_EQ(kSharpAcSwingVLow, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVIgnore);
|
||||
EXPECT_EQ(kSharpAcSwingVIgnore, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
// Lowest/Coanda only works in Heat mode.
|
||||
ac.setMode(kSharpAcCool);
|
||||
ac.setSwingV(kSharpAcSwingVLowest);
|
||||
EXPECT_EQ(kSharpAcSwingVLow, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
ac.setModel(sharp_ac_remote_model_t::A907); // Model A907 has heat mode.
|
||||
ac.setMode(kSharpAcHeat);
|
||||
EXPECT_EQ(kSharpAcHeat, ac.getMode());
|
||||
ac.setSwingV(kSharpAcSwingVLowest);
|
||||
EXPECT_EQ(kSharpAcSwingVLowest, ac.getSwingV());
|
||||
|
||||
// Check we can force Coanda in Cool mode.
|
||||
ac.setMode(kSharpAcCool);
|
||||
ASSERT_EQ(kSharpAcSwingVCoanda, kSharpAcSwingVLowest);
|
||||
ac.setSwingV(kSharpAcSwingVCoanda, true);
|
||||
EXPECT_EQ(kSharpAcSwingVCoanda, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
EXPECT_EQ(kSharpAcCool, ac.getMode());
|
||||
|
||||
// Real messages/states
|
||||
// ref: https://github.com/crankyoldgit/IRremoteESP8266/discussions/1590#discussioncomment-1254748
|
||||
ac.stateReset();
|
||||
const uint8_t coanda_heat_on[13] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xC8, 0x31, 0x21,
|
||||
0x0A, 0x0E, 0x80, 0x06, 0xF4, 0x81};
|
||||
ac.setRaw(coanda_heat_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 1 (Heat), Temp: 23C, Fan: 2 (Auto), "
|
||||
"Swing(V): 6 (Lowest), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t coanda_cool_on[13] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x31, 0x22,
|
||||
0x0A, 0x0E, 0x80, 0x06, 0xF4, 0x41};
|
||||
ac.setRaw(coanda_cool_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 22C, Fan: 2 (Auto), "
|
||||
"Swing(V): 6 (Highest), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestSharpAcClass, Ion) {
|
||||
@@ -1005,8 +1070,8 @@ TEST(TestSharpAcClass, Timers) {
|
||||
EXPECT_TRUE(ac.isPowerSpecial());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off, Off Timer: 08:30",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: On, Light: -, Clean: Off, Off Timer: 08:30",
|
||||
ac.toString());
|
||||
|
||||
// ref: https://docs.google.com/spreadsheets/d/1otzVFM5_tegrZ4ROCLgQ_jvJaWCDlZs1vC-YuR1FFXM/edit#gid=0&range=E80
|
||||
@@ -1020,7 +1085,7 @@ TEST(TestSharpAcClass, Timers) {
|
||||
EXPECT_TRUE(ac.isPowerSpecial());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off, "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off, "
|
||||
"On Timer: 12:00",
|
||||
ac.toString());
|
||||
}
|
||||
@@ -1058,13 +1123,13 @@ TEST(TestSharpAcClass, Clean) {
|
||||
EXPECT_TRUE(ac.getClean());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: On",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: On",
|
||||
ac.toString());
|
||||
ac.setRaw(clean_off_state);
|
||||
EXPECT_FALSE(ac.getClean());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
// Try constructing the clean on state.
|
||||
@@ -1084,13 +1149,13 @@ TEST(TestSharpAcClass, Clean) {
|
||||
ac.setPower(false);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
// Clean ON
|
||||
ac.setClean(true);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: On",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: On",
|
||||
ac.toString());
|
||||
// Clean OFF (state is identical to `off_msg`).
|
||||
// i.e. It just clears the clean settings & turns off the device.
|
||||
@@ -1098,25 +1163,25 @@ TEST(TestSharpAcClass, Clean) {
|
||||
ac.setPower(false, true);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
// Clean ON
|
||||
ac.setClean(true);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: On",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: On",
|
||||
ac.toString());
|
||||
// AC OFF
|
||||
ac.off();
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
// AC ON (Mode Cool, Temp 25, Ion OFF, Fan 7)
|
||||
ac.on();
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: On, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@@ -1126,7 +1191,7 @@ TEST(TestSharpAcClass, Issue1309) {
|
||||
ac.stateReset();
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 0 (UNKNOWN), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t issue1309_on[13] = {
|
||||
@@ -1135,7 +1200,7 @@ TEST(TestSharpAcClass, Issue1309) {
|
||||
ac.setRaw(issue1309_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (A705), Power: On, Mode: 2 (Cool), Temp: 16C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
EXPECT_STATE_EQ(issue1309_on, ac.getRaw(), kSharpAcBits);
|
||||
|
||||
@@ -1147,7 +1212,7 @@ TEST(TestSharpAcClass, Issue1309) {
|
||||
ac.on();
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (A705), Power: On, Mode: 2 (Cool), Temp: 16C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@@ -1200,13 +1265,13 @@ TEST(TestSharpAcClass, Issue1387Power) {
|
||||
EXPECT_STATE_EQ(real_off, ac.getRaw(), kSharpAcBits);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: Off, Mode: 2 (Cool), Temp: 27C, Fan: 3 (Low), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
// Create the same off state.
|
||||
ac.setPower(true, ac.getPower());
|
||||
EXPECT_STATE_EQ(real_on, ac.getRaw(), kSharpAcBits);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 3 (Low), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user