Skip to content

Commit 8b1bfc3

Browse files
authored
Gree YAP0F8 (Detected as Kelvinator) vertical position set support (crankyoldgit#1756)
This should not break the compatibility since the SwingV option is getting expanded and the bit indicating auto is still set correctly.
1 parent 6bc095a commit 8b1bfc3

File tree

7 files changed

+124
-33
lines changed

7 files changed

+124
-33
lines changed

examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void setup() {
5757
ac.setFan(1);
5858
ac.setMode(kKelvinatorCool);
5959
ac.setTemp(26);
60-
ac.setSwingVertical(false);
60+
ac.setSwingVertical(false, kKelvinatorSwingVOff);
6161
ac.setSwingHorizontal(true);
6262
ac.setXFan(true);
6363
ac.setIonFilter(false);

src/IRac.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1465,7 +1465,8 @@ void IRac::kelvinator(IRKelvinatorAC *ac,
14651465
ac->setMode(ac->convertMode(mode));
14661466
ac->setTemp(degrees);
14671467
ac->setFan((uint8_t)fan); // No conversion needed.
1468-
ac->setSwingVertical((int8_t)swingv >= 0);
1468+
ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag.
1469+
ac->convertSwingV(swingv));
14691470
ac->setSwingHorizontal((int8_t)swingh >= 0);
14701471
ac->setQuiet(quiet);
14711472
ac->setTurbo(turbo);

src/ir_Kelvinator.cpp

+66-10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ using irutils::addLabeledString;
5353
using irutils::addModeToString;
5454
using irutils::addFanToString;
5555
using irutils::addTempToString;
56+
using irutils::addSwingVToString;
5657

5758
#if SEND_KELVINATOR
5859
/// Send a Kelvinator A/C message.
@@ -274,24 +275,55 @@ void IRKelvinatorAC::setMode(const uint8_t mode) {
274275
}
275276
}
276277

277-
/// Control the current vertical swing setting.
278-
/// @param[in] on The desired setting.
279-
void IRKelvinatorAC::setSwingVertical(const bool on) {
280-
_.SwingV = on;
281-
_.VentSwing = (on || _.SwingH);
278+
/// Set the Vertical Swing mode of the A/C.
279+
/// @param[in] automatic Do we use the automatic setting?
280+
/// @param[in] position The position/mode to set the vanes to.
281+
void IRKelvinatorAC::setSwingVertical(const bool automatic,
282+
const uint8_t position) {
283+
_.SwingAuto = (automatic || _.SwingH);
284+
uint8_t new_position = position;
285+
if (!automatic) {
286+
switch (position) {
287+
case kKelvinatorSwingVHighest:
288+
case kKelvinatorSwingVUpperMiddle:
289+
case kKelvinatorSwingVMiddle:
290+
case kKelvinatorSwingVLowerMiddle:
291+
case kKelvinatorSwingVLowest:
292+
break;
293+
default:
294+
new_position = kKelvinatorSwingVOff;
295+
}
296+
} else {
297+
switch (position) {
298+
case kKelvinatorSwingVAuto:
299+
case kKelvinatorSwingVLowAuto:
300+
case kKelvinatorSwingVMiddleAuto:
301+
case kKelvinatorSwingVHighAuto:
302+
break;
303+
default:
304+
new_position = kKelvinatorSwingVAuto;
305+
}
306+
}
307+
_.SwingV = new_position;
282308
}
283309

284-
/// Is the vertical swing setting on?
285-
/// @return The current value.
286-
bool IRKelvinatorAC::getSwingVertical(void) const {
310+
/// Get the Vertical Swing Automatic mode setting of the A/C.
311+
/// @return true, the setting is on. false, the setting is off.
312+
bool IRKelvinatorAC::getSwingVerticalAuto(void) const {
313+
return _.SwingV & 0b0001;
314+
}
315+
316+
/// Get the Vertical Swing position setting of the A/C.
317+
/// @return The native position/mode.
318+
uint8_t IRKelvinatorAC::getSwingVerticalPosition(void) const {
287319
return _.SwingV;
288320
}
289321

290322
/// Control the current horizontal swing setting.
291323
/// @param[in] on The desired setting.
292324
void IRKelvinatorAC::setSwingHorizontal(const bool on) {
293325
_.SwingH = on;
294-
_.VentSwing = (on || _.SwingV);
326+
_.SwingAuto = (on || (_.SwingV & 0b0001));
295327
}
296328

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

413+
/// Convert a stdAc::swingv_t enum into it's native setting.
414+
/// @param[in] swingv The enum to be converted.
415+
/// @return The native equivalent of the enum.
416+
uint8_t IRKelvinatorAC::convertSwingV(const stdAc::swingv_t swingv) {
417+
switch (swingv) {
418+
case stdAc::swingv_t::kHighest: return kKelvinatorSwingVHighest;
419+
case stdAc::swingv_t::kHigh: return kKelvinatorSwingVHighAuto;
420+
case stdAc::swingv_t::kMiddle: return kKelvinatorSwingVMiddle;
421+
case stdAc::swingv_t::kLow: return kKelvinatorSwingVLowAuto;
422+
case stdAc::swingv_t::kLowest: return kKelvinatorSwingVLowest;
423+
default: return kKelvinatorSwingVAuto;
424+
}
425+
}
426+
381427
/// Convert a native mode to it's stdAc::opmode_t equivalent.
382428
/// @param[in] mode A native operating mode value.
383429
/// @return The stdAc::opmode_t equivalent.
@@ -442,7 +488,17 @@ String IRKelvinatorAC::toString(void) const {
442488
result += addBoolToString(_.IonFilter, kIonStr);
443489
result += addBoolToString(_.Light, kLightStr);
444490
result += addBoolToString(_.SwingH, kSwingHStr);
445-
result += addBoolToString(_.SwingV, kSwingVStr);
491+
result += addSwingVToString(_.SwingV, kKelvinatorSwingVAuto,
492+
kKelvinatorSwingVHighest,
493+
kKelvinatorSwingVHighAuto,
494+
kKelvinatorSwingVUpperMiddle,
495+
kKelvinatorSwingVMiddle,
496+
kKelvinatorSwingVLowerMiddle,
497+
kKelvinatorSwingVLowAuto,
498+
kKelvinatorSwingVLowest,
499+
kKelvinatorSwingVOff,
500+
kKelvinatorSwingVAuto, kKelvinatorSwingVAuto,
501+
kKelvinatorSwingVAuto);
446502
return result;
447503
}
448504

src/ir_Kelvinator.h

+19-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// Brand: Kelvinator, Model: KSV70HRC A/C
1515
// Brand: Kelvinator, Model: KSV80HRC A/C
1616
// Brand: Green, Model: YAPOF3 remote
17+
// Brand: Gree, Model: YAP0F8 remote
1718
// Brand: Sharp, Model: YB1FA remote
1819
// Brand: Sharp, Model: A5VEY A/C
1920

@@ -39,7 +40,7 @@ union KelvinatorProtocol{
3940
uint8_t Mode :3;
4041
uint8_t Power :1;
4142
uint8_t BasicFan :2;
42-
uint8_t VentSwing :1;
43+
uint8_t SwingAuto :1;
4344
uint8_t :1; // Sleep Modes 1 & 3 (1 = On, 0 = Off)
4445
// Byte 1
4546
uint8_t Temp :4; // Degrees C.
@@ -56,8 +57,7 @@ union KelvinatorProtocol{
5657
uint8_t :2; // End of command block (B01)
5758
// (B010 marker and a gap of 20ms)
5859
// Byte 4
59-
uint8_t SwingV :1;
60-
uint8_t :3;
60+
uint8_t SwingV :4;
6161
uint8_t SwingH :1;
6262
uint8_t :3;
6363
// Byte 5~6
@@ -103,6 +103,17 @@ const uint8_t kKelvinatorMinTemp = 16; // 16C
103103
const uint8_t kKelvinatorMaxTemp = 30; // 30C
104104
const uint8_t kKelvinatorAutoTemp = 25; // 25C
105105

106+
const uint8_t kKelvinatorSwingVOff = 0b0000; // 0
107+
const uint8_t kKelvinatorSwingVAuto = 0b0001; // 1
108+
const uint8_t kKelvinatorSwingVHighest = 0b0010; // 2
109+
const uint8_t kKelvinatorSwingVUpperMiddle = 0b0011; // 3
110+
const uint8_t kKelvinatorSwingVMiddle = 0b0100; // 4
111+
const uint8_t kKelvinatorSwingVLowerMiddle = 0b0101; // 5
112+
const uint8_t kKelvinatorSwingVLowest = 0b0110; // 6
113+
const uint8_t kKelvinatorSwingVLowAuto = 0b0111; // 7
114+
const uint8_t kKelvinatorSwingVMiddleAuto = 0b1001; // 9
115+
const uint8_t kKelvinatorSwingVHighAuto = 0b1011; // 11
116+
106117
// Legacy defines (Deprecated)
107118
#define KELVINATOR_MIN_TEMP kKelvinatorMinTemp
108119
#define KELVINATOR_MAX_TEMP kKelvinatorMaxTemp
@@ -142,8 +153,11 @@ class IRKelvinatorAC {
142153
uint8_t getFan(void) const;
143154
void setMode(const uint8_t mode);
144155
uint8_t getMode(void) const;
145-
void setSwingVertical(const bool on);
146-
bool getSwingVertical(void) const;
156+
void setSwingVertical(const bool automatic, const uint8_t position);
157+
bool getSwingVerticalAuto(void) const;
158+
uint8_t getSwingVerticalPosition(void) const;
159+
static uint8_t convertSwingV(const stdAc::swingv_t swingv);
160+
static stdAc::swingv_t toCommonSwingV(const uint8_t pos);
147161
void setSwingHorizontal(const bool on);
148162
bool getSwingHorizontal(void) const;
149163
void setQuiet(const bool on);

test/IRac_test.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ TEST(TestIRac, Kelvinator) {
10761076
char expected[] =
10771077
"Power: On, Mode: 1 (Cool), Temp: 19C, Fan: 3 (Medium), Turbo: Off, "
10781078
"Quiet: Off, XFan: On, Ion: On, Light: On, "
1079-
"Swing(H): Off, Swing(V): Off";
1079+
"Swing(H): Off, Swing(V): 0 (Off)";
10801080

10811081
ac.begin();
10821082
irac.kelvinator(&ac,

test/ir_Kelvinator_test.cpp

+34-14
Original file line numberDiff line numberDiff line change
@@ -251,23 +251,43 @@ TEST(TestKelvinatorClass, VaneSwing) {
251251
irkelv.begin();
252252

253253
irkelv.setSwingHorizontal(true);
254-
irkelv.setSwingVertical(false);
254+
EXPECT_TRUE(irkelv.getSwingHorizontal());
255255

256-
irkelv.setSwingHorizontal(true);
256+
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
257+
EXPECT_EQ(kKelvinatorSwingVOff, irkelv.getSwingVerticalPosition());
258+
259+
irkelv.setSwingVertical(true, kKelvinatorSwingVAuto);
260+
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
261+
EXPECT_EQ(kKelvinatorSwingVAuto, irkelv.getSwingVerticalPosition());
257262
EXPECT_TRUE(irkelv.getSwingHorizontal());
258-
EXPECT_FALSE(irkelv.getSwingVertical());
259263

260-
irkelv.setSwingVertical(true);
264+
irkelv.setSwingVertical(false, kKelvinatorSwingVMiddle);
265+
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
266+
EXPECT_EQ(kKelvinatorSwingVMiddle, irkelv.getSwingVerticalPosition());
261267
EXPECT_TRUE(irkelv.getSwingHorizontal());
262-
EXPECT_TRUE(irkelv.getSwingVertical());
263268

264269
irkelv.setSwingHorizontal(false);
265270
EXPECT_FALSE(irkelv.getSwingHorizontal());
266-
EXPECT_TRUE(irkelv.getSwingVertical());
267271

268-
irkelv.setSwingVertical(false);
272+
irkelv.setSwingVertical(true, kKelvinatorSwingVLowAuto);
273+
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
274+
EXPECT_EQ(kKelvinatorSwingVLowAuto, irkelv.getSwingVerticalPosition());
269275
EXPECT_FALSE(irkelv.getSwingHorizontal());
270-
EXPECT_FALSE(irkelv.getSwingVertical());
276+
277+
// Out of bounds.
278+
irkelv.setSwingVertical(false, 255);
279+
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
280+
EXPECT_EQ(kKelvinatorSwingVOff, irkelv.getSwingVerticalPosition());
281+
irkelv.setSwingVertical(false, kKelvinatorSwingVAuto);
282+
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
283+
EXPECT_EQ(kKelvinatorSwingVOff, irkelv.getSwingVerticalPosition());
284+
285+
irkelv.setSwingVertical(true, 255);
286+
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
287+
EXPECT_EQ(kKelvinatorSwingVAuto, irkelv.getSwingVerticalPosition());
288+
irkelv.setSwingVertical(true, kKelvinatorSwingVLowest);
289+
EXPECT_TRUE(irkelv.getSwingVerticalAuto());
290+
EXPECT_EQ(kKelvinatorSwingVAuto, irkelv.getSwingVerticalPosition());
271291
}
272292

273293
TEST(TestKelvinatorClass, QuietMode) {
@@ -425,7 +445,7 @@ TEST(TestKelvinatorClass, HumanReadable) {
425445
EXPECT_EQ(
426446
"Power: Off, Mode: 0 (Auto), Temp: 16C, Fan: 0 (Auto), Turbo: Off, "
427447
"Quiet: Off, XFan: Off, Ion: Off, Light: Off, "
428-
"Swing(H): Off, Swing(V): Off",
448+
"Swing(H): Off, Swing(V): 0 (Off)",
429449
irkelv.toString());
430450
irkelv.on();
431451
irkelv.setMode(kKelvinatorCool);
@@ -438,7 +458,7 @@ TEST(TestKelvinatorClass, HumanReadable) {
438458
EXPECT_EQ(
439459
"Power: On, Mode: 1 (Cool), Temp: 25C, Fan: 5 (High), Turbo: Off, "
440460
"Quiet: Off, XFan: On, Ion: On, Light: On, "
441-
"Swing(H): On, Swing(V): Off",
461+
"Swing(H): On, Swing(V): 0 (Off)",
442462
irkelv.toString());
443463
}
444464

@@ -451,7 +471,7 @@ TEST(TestKelvinatorClass, MessageConstuction) {
451471
irkelv.setFan(1);
452472
irkelv.setMode(kKelvinatorCool);
453473
irkelv.setTemp(27);
454-
irkelv.setSwingVertical(false);
474+
irkelv.setSwingVertical(false, kKelvinatorSwingVOff);
455475
irkelv.setSwingHorizontal(true);
456476
irkelv.setIonFilter(true);
457477
irkelv.setQuiet(false);
@@ -464,7 +484,7 @@ TEST(TestKelvinatorClass, MessageConstuction) {
464484
EXPECT_EQ(1, irkelv.getFan());
465485
EXPECT_EQ(kKelvinatorCool, irkelv.getMode());
466486
EXPECT_EQ(27, irkelv.getTemp());
467-
EXPECT_FALSE(irkelv.getSwingVertical());
487+
EXPECT_FALSE(irkelv.getSwingVerticalAuto());
468488
EXPECT_TRUE(irkelv.getSwingHorizontal());
469489
EXPECT_TRUE(irkelv.getIonFilter());
470490
EXPECT_FALSE(irkelv.getQuiet());
@@ -523,7 +543,7 @@ TEST(TestDecodeKelvinator, NormalSynthetic) {
523543
EXPECT_EQ(
524544
"Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, "
525545
"Quiet: Off, XFan: On, Ion: Off, Light: Off, "
526-
"Swing(H): Off, Swing(V): Off",
546+
"Swing(H): Off, Swing(V): 0 (Off)",
527547
IRAcUtils::resultAcToString(&irsend.capture));
528548
stdAc::state_t r, p;
529549
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
@@ -541,7 +561,7 @@ TEST(TestKelvinatorClass, toCommon) {
541561
ac.setTurbo(true);
542562
ac.setLight(true);
543563
ac.setSwingHorizontal(false);
544-
ac.setSwingVertical(true);
564+
ac.setSwingVertical(true, kKelvinatorSwingVAuto);
545565

546566
// Now test it.
547567
ASSERT_EQ(decode_type_t::KELVINATOR, ac.toCommon().protocol);

tools/code_to_raw_test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ unittest_success "${CODE_TO_RAW} --protocol SAMSUNG --code 0xE0E09966" "${OUT}"
5656
read -r -d '' OUT << xEOMx
5757
Code type: 18 (KELVINATOR)
5858
Code bits: 128
59-
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
59+
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)
6060
6161
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
6262
uint8_t state[16] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xF0};

0 commit comments

Comments
 (0)