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

Gree YAP0F8 (Detected as Kelvinator) vertical position set support #1756

Merged
merged 6 commits into from
Feb 12, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void setup() {
ac.setFan(1);
ac.setMode(kKelvinatorCool);
ac.setTemp(26);
ac.setSwingVertical(false);
ac.setSwingVertical(false, kKelvinatorSwingVOff);
ac.setSwingHorizontal(true);
ac.setXFan(true);
ac.setIonFilter(false);
Expand Down
3 changes: 2 additions & 1 deletion src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1465,7 +1465,8 @@ void IRac::kelvinator(IRKelvinatorAC *ac,
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
ac->setFan((uint8_t)fan); // No conversion needed.
ac->setSwingVertical((int8_t)swingv >= 0);
ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag.
ac->convertSwingV(swingv));
ac->setSwingHorizontal((int8_t)swingh >= 0);
ac->setQuiet(quiet);
ac->setTurbo(turbo);
Expand Down
76 changes: 66 additions & 10 deletions src/ir_Kelvinator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ using irutils::addLabeledString;
using irutils::addModeToString;
using irutils::addFanToString;
using irutils::addTempToString;
using irutils::addSwingVToString;

#if SEND_KELVINATOR
/// Send a Kelvinator A/C message.
Expand Down Expand Up @@ -274,24 +275,55 @@ void IRKelvinatorAC::setMode(const uint8_t mode) {
}
}

/// Control the current vertical swing setting.
/// @param[in] on The desired setting.
void IRKelvinatorAC::setSwingVertical(const bool on) {
_.SwingV = on;
_.VentSwing = (on || _.SwingH);
/// Set the Vertical Swing mode of the A/C.
/// @param[in] automatic Do we use the automatic setting?
/// @param[in] position The position/mode to set the vanes to.
void IRKelvinatorAC::setSwingVertical(const bool automatic,
const uint8_t position) {
_.SwingAuto = (automatic || _.SwingH);
uint8_t new_position = position;
if (!automatic) {
switch (position) {
case kKelvinatorSwingVHighest:
case kKelvinatorSwingVUpperMiddle:
case kKelvinatorSwingVMiddle:
case kKelvinatorSwingVLowerMiddle:
case kKelvinatorSwingVLowest:
break;
default:
new_position = kKelvinatorSwingVOff;
}
} else {
switch (position) {
case kKelvinatorSwingVAuto:
case kKelvinatorSwingVLowAuto:
case kKelvinatorSwingVMiddleAuto:
case kKelvinatorSwingVHighAuto:
break;
default:
new_position = kKelvinatorSwingVAuto;
}
}
_.SwingV = new_position;
}

/// Is the vertical swing setting on?
/// @return The current value.
bool IRKelvinatorAC::getSwingVertical(void) const {
/// Get the Vertical Swing Automatic mode setting of the A/C.
/// @return true, the setting is on. false, the setting is off.
bool IRKelvinatorAC::getSwingVerticalAuto(void) const {
return _.SwingV & 0b0001;
}

/// Get the Vertical Swing position setting of the A/C.
/// @return The native position/mode.
uint8_t IRKelvinatorAC::getSwingVerticalPosition(void) const {
return _.SwingV;
}

/// Control the current horizontal swing setting.
/// @param[in] on The desired setting.
void IRKelvinatorAC::setSwingHorizontal(const bool on) {
_.SwingH = on;
_.VentSwing = (on || _.SwingV);
_.SwingAuto = (on || (_.SwingV & 0b0001));
}

/// Is the horizontal swing setting on?
Expand Down Expand Up @@ -378,6 +410,20 @@ uint8_t IRKelvinatorAC::convertMode(const stdAc::opmode_t mode) {
}
}

/// Convert a stdAc::swingv_t enum into it's native setting.
/// @param[in] swingv The enum to be converted.
/// @return The native equivalent of the enum.
uint8_t IRKelvinatorAC::convertSwingV(const stdAc::swingv_t swingv) {
switch (swingv) {
case stdAc::swingv_t::kHighest: return kKelvinatorSwingVHighest;
case stdAc::swingv_t::kHigh: return kKelvinatorSwingVHighAuto;
case stdAc::swingv_t::kMiddle: return kKelvinatorSwingVMiddle;
case stdAc::swingv_t::kLow: return kKelvinatorSwingVLowAuto;
case stdAc::swingv_t::kLowest: return kKelvinatorSwingVLowest;
default: return kKelvinatorSwingVAuto;
}
}

/// Convert a native mode to it's stdAc::opmode_t equivalent.
/// @param[in] mode A native operating mode value.
/// @return The stdAc::opmode_t equivalent.
Expand Down Expand Up @@ -442,7 +488,17 @@ String IRKelvinatorAC::toString(void) const {
result += addBoolToString(_.IonFilter, kIonStr);
result += addBoolToString(_.Light, kLightStr);
result += addBoolToString(_.SwingH, kSwingHStr);
result += addBoolToString(_.SwingV, kSwingVStr);
result += addSwingVToString(_.SwingV, kKelvinatorSwingVAuto,
kKelvinatorSwingVHighest,
kKelvinatorSwingVHighAuto,
kKelvinatorSwingVUpperMiddle,
kKelvinatorSwingVMiddle,
kKelvinatorSwingVLowerMiddle,
kKelvinatorSwingVLowAuto,
kKelvinatorSwingVLowest,
kKelvinatorSwingVOff,
kKelvinatorSwingVAuto, kKelvinatorSwingVAuto,
kKelvinatorSwingVAuto);
return result;
}

Expand Down
24 changes: 19 additions & 5 deletions src/ir_Kelvinator.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// Brand: Kelvinator, Model: KSV70HRC A/C
// Brand: Kelvinator, Model: KSV80HRC A/C
// Brand: Green, Model: YAPOF3 remote
// Brand: Gree, Model: YAP0F8 remote
// Brand: Sharp, Model: YB1FA remote
// Brand: Sharp, Model: A5VEY A/C

Expand All @@ -39,7 +40,7 @@ union KelvinatorProtocol{
uint8_t Mode :3;
uint8_t Power :1;
uint8_t BasicFan :2;
uint8_t VentSwing :1;
uint8_t SwingAuto :1;
uint8_t :1; // Sleep Modes 1 & 3 (1 = On, 0 = Off)
// Byte 1
uint8_t Temp :4; // Degrees C.
Expand All @@ -56,8 +57,7 @@ union KelvinatorProtocol{
uint8_t :2; // End of command block (B01)
// (B010 marker and a gap of 20ms)
// Byte 4
uint8_t SwingV :1;
uint8_t :3;
uint8_t SwingV :4;
uint8_t SwingH :1;
uint8_t :3;
// Byte 5~6
Expand Down Expand Up @@ -103,6 +103,17 @@ const uint8_t kKelvinatorMinTemp = 16; // 16C
const uint8_t kKelvinatorMaxTemp = 30; // 30C
const uint8_t kKelvinatorAutoTemp = 25; // 25C

const uint8_t kKelvinatorSwingVOff = 0b0000; // 0
const uint8_t kKelvinatorSwingVAuto = 0b0001; // 1
const uint8_t kKelvinatorSwingVHighest = 0b0010; // 2
const uint8_t kKelvinatorSwingVUpperMiddle = 0b0011; // 3
const uint8_t kKelvinatorSwingVMiddle = 0b0100; // 4
const uint8_t kKelvinatorSwingVLowerMiddle = 0b0101; // 5
const uint8_t kKelvinatorSwingVLowest = 0b0110; // 6
const uint8_t kKelvinatorSwingVLowAuto = 0b0111; // 7
const uint8_t kKelvinatorSwingVMiddleAuto = 0b1001; // 9
const uint8_t kKelvinatorSwingVHighAuto = 0b1011; // 11

// Legacy defines (Deprecated)
#define KELVINATOR_MIN_TEMP kKelvinatorMinTemp
#define KELVINATOR_MAX_TEMP kKelvinatorMaxTemp
Expand Down Expand Up @@ -142,8 +153,11 @@ class IRKelvinatorAC {
uint8_t getFan(void) const;
void setMode(const uint8_t mode);
uint8_t getMode(void) const;
void setSwingVertical(const bool on);
bool getSwingVertical(void) const;
void setSwingVertical(const bool automatic, const uint8_t position);
bool getSwingVerticalAuto(void) const;
uint8_t getSwingVerticalPosition(void) const;
static uint8_t convertSwingV(const stdAc::swingv_t swingv);
static stdAc::swingv_t toCommonSwingV(const uint8_t pos);
void setSwingHorizontal(const bool on);
bool getSwingHorizontal(void) const;
void setQuiet(const bool on);
Expand Down
2 changes: 1 addition & 1 deletion test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ TEST(TestIRac, Kelvinator) {
char expected[] =
"Power: On, Mode: 1 (Cool), Temp: 19C, Fan: 3 (Medium), Turbo: Off, "
"Quiet: Off, XFan: On, Ion: On, Light: On, "
"Swing(H): Off, Swing(V): Off";
"Swing(H): Off, Swing(V): 0 (Off)";

ac.begin();
irac.kelvinator(&ac,
Expand Down
48 changes: 34 additions & 14 deletions test/ir_Kelvinator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,23 +251,43 @@ TEST(TestKelvinatorClass, VaneSwing) {
irkelv.begin();

irkelv.setSwingHorizontal(true);
irkelv.setSwingVertical(false);
EXPECT_TRUE(irkelv.getSwingHorizontal());

irkelv.setSwingHorizontal(true);
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVOff, irkelv.getSwingVerticalPosition());

irkelv.setSwingVertical(true, kKelvinatorSwingVAuto);
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVAuto, irkelv.getSwingVerticalPosition());
EXPECT_TRUE(irkelv.getSwingHorizontal());
EXPECT_FALSE(irkelv.getSwingVertical());

irkelv.setSwingVertical(true);
irkelv.setSwingVertical(false, kKelvinatorSwingVMiddle);
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVMiddle, irkelv.getSwingVerticalPosition());
EXPECT_TRUE(irkelv.getSwingHorizontal());
EXPECT_TRUE(irkelv.getSwingVertical());

irkelv.setSwingHorizontal(false);
EXPECT_FALSE(irkelv.getSwingHorizontal());
EXPECT_TRUE(irkelv.getSwingVertical());

irkelv.setSwingVertical(false);
irkelv.setSwingVertical(true, kKelvinatorSwingVLowAuto);
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVLowAuto, irkelv.getSwingVerticalPosition());
EXPECT_FALSE(irkelv.getSwingHorizontal());
EXPECT_FALSE(irkelv.getSwingVertical());

// Out of bounds.
irkelv.setSwingVertical(false, 255);
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVOff, irkelv.getSwingVerticalPosition());
irkelv.setSwingVertical(false, kKelvinatorSwingVAuto);
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVOff, irkelv.getSwingVerticalPosition());

irkelv.setSwingVertical(true, 255);
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVAuto, irkelv.getSwingVerticalPosition());
irkelv.setSwingVertical(true, kKelvinatorSwingVLowest);
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
EXPECT_EQ(kKelvinatorSwingVAuto, irkelv.getSwingVerticalPosition());
}

TEST(TestKelvinatorClass, QuietMode) {
Expand Down Expand Up @@ -425,7 +445,7 @@ TEST(TestKelvinatorClass, HumanReadable) {
EXPECT_EQ(
"Power: Off, Mode: 0 (Auto), Temp: 16C, Fan: 0 (Auto), Turbo: Off, "
"Quiet: Off, XFan: Off, Ion: Off, Light: Off, "
"Swing(H): Off, Swing(V): Off",
"Swing(H): Off, Swing(V): 0 (Off)",
irkelv.toString());
irkelv.on();
irkelv.setMode(kKelvinatorCool);
Expand All @@ -438,7 +458,7 @@ TEST(TestKelvinatorClass, HumanReadable) {
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 25C, Fan: 5 (High), Turbo: Off, "
"Quiet: Off, XFan: On, Ion: On, Light: On, "
"Swing(H): On, Swing(V): Off",
"Swing(H): On, Swing(V): 0 (Off)",
irkelv.toString());
}

Expand All @@ -451,7 +471,7 @@ TEST(TestKelvinatorClass, MessageConstuction) {
irkelv.setFan(1);
irkelv.setMode(kKelvinatorCool);
irkelv.setTemp(27);
irkelv.setSwingVertical(false);
irkelv.setSwingVertical(false, kKelvinatorSwingVOff);
irkelv.setSwingHorizontal(true);
irkelv.setIonFilter(true);
irkelv.setQuiet(false);
Expand All @@ -464,7 +484,7 @@ TEST(TestKelvinatorClass, MessageConstuction) {
EXPECT_EQ(1, irkelv.getFan());
EXPECT_EQ(kKelvinatorCool, irkelv.getMode());
EXPECT_EQ(27, irkelv.getTemp());
EXPECT_FALSE(irkelv.getSwingVertical());
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
EXPECT_TRUE(irkelv.getSwingHorizontal());
EXPECT_TRUE(irkelv.getIonFilter());
EXPECT_FALSE(irkelv.getQuiet());
Expand Down Expand Up @@ -523,7 +543,7 @@ TEST(TestDecodeKelvinator, NormalSynthetic) {
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, "
"Quiet: Off, XFan: On, Ion: Off, Light: Off, "
"Swing(H): Off, Swing(V): Off",
"Swing(H): Off, Swing(V): 0 (Off)",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
Expand All @@ -541,7 +561,7 @@ TEST(TestKelvinatorClass, toCommon) {
ac.setTurbo(true);
ac.setLight(true);
ac.setSwingHorizontal(false);
ac.setSwingVertical(true);
ac.setSwingVertical(true, kKelvinatorSwingVAuto);

// Now test it.
ASSERT_EQ(decode_type_t::KELVINATOR, ac.toCommon().protocol);
Expand Down
2 changes: 1 addition & 1 deletion tools/code_to_raw_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ unittest_success "${CODE_TO_RAW} --protocol SAMSUNG --code 0xE0E09966" "${OUT}"
read -r -d '' OUT << xEOMx
Code type: 18 (KELVINATOR)
Code bits: 128
Description: Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, Quiet: Off, XFan: On, Ion: Off, Light: Off, Swing(H): Off, Swing(V): Off
Description: Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, Quiet: Off, XFan: On, Ion: Off, Light: Off, Swing(H): Off, Swing(V): 0 (Off)

uint16_t rawData[280] = {9010, 4504, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 19974, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 39950, 9010, 4504, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 19974, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 1530, 680, 39950 }; // KELVINATOR
uint8_t state[16] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xF0};
Expand Down