mirror of https://github.com/arendst/Tasmota.git
426 lines
13 KiB
C++
426 lines
13 KiB
C++
// Copyright 2020 crankyoldgit
|
|
|
|
#include "ir_Voltas.h"
|
|
#include "IRac.h"
|
|
#include "IRrecv.h"
|
|
#include "IRrecv_test.h"
|
|
#include "IRsend.h"
|
|
#include "IRsend_test.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
// Tests for decodeVoltas().
|
|
|
|
TEST(TestDecodeVoltas, RealExample) {
|
|
IRsendTest irsend(kGpioUnused);
|
|
IRrecv irrecv(kGpioUnused);
|
|
const uint16_t rawData[161] = {
|
|
1002, 584, 1000, 586, 1000, 2568, 1002, 2570, 1002, 586, 998, 588, 1000,
|
|
2568, 1002, 2570, 1002, 2572, 1002, 584, 1002, 586, 1000, 584, 1000, 586,
|
|
1002, 2568, 1004, 584, 1000, 586, 1002, 2568, 1002, 584, 1002, 584, 1004,
|
|
584, 1000, 2568, 1002, 586, 1000, 586, 998, 590, 998, 584, 1002, 584,
|
|
1000, 586, 1000, 2570, 1002, 2568, 1004, 584, 1000, 584, 1002, 584, 1002,
|
|
582, 1004, 584, 1002, 2568, 1002, 2570, 1004, 2570, 1000, 586, 1002, 2568,
|
|
1004, 2568, 1006, 584, 1000, 584, 1002, 2568, 1002, 2570, 1002, 2568,
|
|
1002, 586, 1002, 2570, 1000, 2570, 1002, 588, 998, 586, 1000, 2568, 1004,
|
|
2568, 1004, 2568, 1002, 588, 998, 2570, 1002, 2568, 1004, 586, 1002, 584,
|
|
1000, 586, 1000, 2570, 1000, 586, 1000, 584, 1002, 586, 1000, 2568, 1004,
|
|
584, 1000, 586, 1000, 586, 1002, 584, 1002, 586, 1000, 586, 1000, 586,
|
|
1000, 586, 1000, 2568, 1002, 2568, 1002, 2568, 1004, 586, 1000, 584,
|
|
1000, 2570, 1004, 2568, 1004, 584, 1002};
|
|
const uint8_t expected[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};
|
|
|
|
irsend.begin();
|
|
irsend.reset();
|
|
irsend.sendRaw(rawData, 161, 38);
|
|
irsend.makeDecodeResult();
|
|
|
|
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
|
ASSERT_EQ(decode_type_t::VOLTAS, irsend.capture.decode_type);
|
|
ASSERT_EQ(kVoltasBits, irsend.capture.bits);
|
|
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 4 (Dry), Temp: 24C, Fan: 4 (Low), "
|
|
"Swing(V): Off, Swing(H): N/A, "
|
|
"Turbo: Off, Econo: Off, WiFi: On, Light: Off, Sleep: Off, "
|
|
"On Timer: Off, Off Timer: Off",
|
|
IRAcUtils::resultAcToString(&irsend.capture));
|
|
stdAc::state_t r, p;
|
|
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
|
}
|
|
|
|
TEST(TestDecodeVoltas, SyntheticExample) {
|
|
IRsendTest irsend(kGpioUnused);
|
|
IRrecv irrecv(kGpioUnused);
|
|
irsend.begin();
|
|
irsend.reset();
|
|
const uint8_t expected[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};
|
|
// power
|
|
irsend.sendVoltas(expected);
|
|
irsend.makeDecodeResult();
|
|
|
|
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
|
EXPECT_EQ(decode_type_t::VOLTAS, irsend.capture.decode_type);
|
|
EXPECT_EQ(kVoltasBits, irsend.capture.bits);
|
|
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
|
|
}
|
|
|
|
TEST(TestUtils, Housekeeping) {
|
|
ASSERT_EQ("VOLTAS", typeToString(decode_type_t::VOLTAS));
|
|
ASSERT_EQ(decode_type_t::VOLTAS, strToDecodeType("VOLTAS"));
|
|
ASSERT_TRUE(hasACState(decode_type_t::VOLTAS));
|
|
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::VOLTAS));
|
|
ASSERT_EQ(kVoltasBits, IRsend::defaultBits(decode_type_t::VOLTAS));
|
|
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::VOLTAS));
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Checksums) {
|
|
const uint8_t valid[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};
|
|
EXPECT_TRUE(IRVoltas::validChecksum(valid));
|
|
EXPECT_FALSE(IRVoltas::validChecksum(valid, kVoltasStateLength - 1));
|
|
EXPECT_EQ(0xE6, IRVoltas::calcChecksum(valid));
|
|
const uint8_t badchecksum[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0x00};
|
|
EXPECT_FALSE(IRVoltas::validChecksum(badchecksum));
|
|
EXPECT_EQ(0xE6, IRVoltas::calcChecksum(badchecksum));
|
|
const uint8_t kReset[kVoltasStateLength] = {
|
|
0x33, 0x28, 0x00, 0x17, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xCB};
|
|
EXPECT_TRUE(IRVoltas::validChecksum(kReset));
|
|
EXPECT_EQ(0xCB, IRVoltas::calcChecksum(kReset));
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, SetandGetRaw) {
|
|
const uint8_t valid[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};
|
|
const uint8_t badchecksum[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0x00};
|
|
IRVoltas ac(kGpioUnused);
|
|
|
|
ac.setRaw(valid);
|
|
EXPECT_STATE_EQ(valid, ac.getRaw(), kVoltasBits);
|
|
ac.setRaw(badchecksum);
|
|
EXPECT_STATE_EQ(valid, ac.getRaw(), kVoltasBits);
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Power) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.on();
|
|
EXPECT_TRUE(ac.getPower());
|
|
|
|
ac.off();
|
|
EXPECT_FALSE(ac.getPower());
|
|
|
|
ac.setPower(true);
|
|
EXPECT_TRUE(ac.getPower());
|
|
|
|
ac.setPower(false);
|
|
EXPECT_FALSE(ac.getPower());
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Wifi) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setWifi(false);
|
|
EXPECT_FALSE(ac.getWifi());
|
|
ac.setWifi(true);
|
|
EXPECT_TRUE(ac.getWifi());
|
|
ac.setWifi(false);
|
|
EXPECT_FALSE(ac.getWifi());
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Turbo) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setTurbo(false);
|
|
EXPECT_FALSE(ac.getTurbo());
|
|
ac.setTurbo(true);
|
|
EXPECT_TRUE(ac.getTurbo());
|
|
ac.setTurbo(false);
|
|
EXPECT_FALSE(ac.getTurbo());
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Sleep) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setSleep(false);
|
|
EXPECT_FALSE(ac.getSleep());
|
|
ac.setSleep(true);
|
|
EXPECT_TRUE(ac.getSleep());
|
|
ac.setSleep(false);
|
|
EXPECT_FALSE(ac.getSleep());
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Econo) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
// Control of econo mode is only available in cool.
|
|
ac.setMode(kVoltasCool);
|
|
ac.setEcono(false);
|
|
EXPECT_FALSE(ac.getEcono());
|
|
ac.setEcono(true);
|
|
EXPECT_TRUE(ac.getEcono());
|
|
ac.setEcono(false);
|
|
EXPECT_FALSE(ac.getEcono());
|
|
ac.setEcono(true);
|
|
ac.setMode(kVoltasHeat); // Control of econo mode should now be disabled.
|
|
EXPECT_FALSE(ac.getEcono());
|
|
ac.setEcono(true);
|
|
EXPECT_FALSE(ac.getEcono());
|
|
}
|
|
|
|
TEST(TestIRVoltasClass, Light) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setLight(false);
|
|
EXPECT_FALSE(ac.getLight());
|
|
ac.setLight(true);
|
|
EXPECT_TRUE(ac.getLight());
|
|
ac.setLight(false);
|
|
EXPECT_FALSE(ac.getLight());
|
|
|
|
const uint8_t light_off[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};
|
|
ac.setRaw(light_off);
|
|
EXPECT_FALSE(ac.getLight());
|
|
const uint8_t light_on[kVoltasStateLength] = {
|
|
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x20, 0xC6};
|
|
ac.setRaw(light_on);
|
|
EXPECT_TRUE(ac.getLight());
|
|
ac.setLight(false);
|
|
EXPECT_STATE_EQ(light_off, ac.getRaw(), kVoltasBits);
|
|
ac.setLight(true);
|
|
EXPECT_STATE_EQ(light_on, ac.getRaw(), kVoltasBits);
|
|
}
|
|
|
|
TEST(TestVoltasClass, OperatingMode) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setMode(kVoltasCool);
|
|
EXPECT_EQ(kVoltasCool, ac.getMode());
|
|
ac.setMode(kVoltasFan);
|
|
EXPECT_EQ(kVoltasFan, ac.getMode());
|
|
ac.setMode(kVoltasDry);
|
|
EXPECT_EQ(kVoltasDry, ac.getMode());
|
|
ac.setMode(kVoltasHeat);
|
|
EXPECT_EQ(kVoltasHeat, ac.getMode());
|
|
|
|
ac.setMode(kVoltasCool - 1);
|
|
EXPECT_EQ(kVoltasCool, ac.getMode());
|
|
|
|
ac.setMode(kVoltasCool + 1);
|
|
EXPECT_EQ(kVoltasCool, ac.getMode());
|
|
|
|
ac.setMode(255);
|
|
EXPECT_EQ(kVoltasCool, ac.getMode());
|
|
}
|
|
|
|
TEST(TestVoltasClass, Temperature) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setTemp(kVoltasMinTemp);
|
|
EXPECT_EQ(kVoltasMinTemp, ac.getTemp());
|
|
|
|
ac.setTemp(kVoltasMinTemp + 1);
|
|
EXPECT_EQ(kVoltasMinTemp + 1, ac.getTemp());
|
|
|
|
ac.setTemp(kVoltasMaxTemp);
|
|
EXPECT_EQ(kVoltasMaxTemp, ac.getTemp());
|
|
|
|
ac.setTemp(kVoltasMinTemp - 1);
|
|
EXPECT_EQ(kVoltasMinTemp, ac.getTemp());
|
|
|
|
ac.setTemp(kVoltasMaxTemp + 1);
|
|
EXPECT_EQ(kVoltasMaxTemp, ac.getTemp());
|
|
|
|
ac.setTemp(23);
|
|
EXPECT_EQ(23, ac.getTemp());
|
|
|
|
ac.setTemp(0);
|
|
EXPECT_EQ(kVoltasMinTemp, ac.getTemp());
|
|
|
|
ac.setTemp(255);
|
|
EXPECT_EQ(kVoltasMaxTemp, ac.getTemp());
|
|
}
|
|
|
|
TEST(TestVoltasClass, FanSpeed) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
ac.setMode(kVoltasCool); // All fan speeds are allowed in cool mode.
|
|
ac.setFan(kVoltasFanLow);
|
|
|
|
ac.setFan(kVoltasFanAuto);
|
|
EXPECT_EQ(kVoltasFanAuto, ac.getFan());
|
|
|
|
ac.setFan(kVoltasFanLow);
|
|
EXPECT_EQ(kVoltasFanLow, ac.getFan());
|
|
ac.setFan(kVoltasFanMed);
|
|
EXPECT_EQ(kVoltasFanMed, ac.getFan());
|
|
ac.setFan(kVoltasFanHigh);
|
|
EXPECT_EQ(kVoltasFanHigh, ac.getFan());
|
|
|
|
ac.setFan(0);
|
|
EXPECT_EQ(kVoltasFanAuto, ac.getFan());
|
|
|
|
ac.setFan(255);
|
|
EXPECT_EQ(kVoltasFanAuto, ac.getFan());
|
|
|
|
// Confirm auto speed isn't operable in Fan mode.
|
|
ac.setMode(kVoltasFan);
|
|
EXPECT_NE(kVoltasFanAuto, ac.getFan());
|
|
ac.setFan(kVoltasFanLow);
|
|
EXPECT_EQ(kVoltasFanLow, ac.getFan());
|
|
ac.setFan(kVoltasFanMed);
|
|
EXPECT_EQ(kVoltasFanMed, ac.getFan());
|
|
ac.setFan(kVoltasFanHigh);
|
|
EXPECT_EQ(kVoltasFanHigh, ac.getFan());
|
|
ac.setFan(kVoltasFanAuto);
|
|
EXPECT_NE(kVoltasFanAuto, ac.getFan());
|
|
}
|
|
|
|
TEST(TestVoltasClass, SwingV) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
|
|
ac.setSwingV(true);
|
|
EXPECT_TRUE(ac.getSwingV());
|
|
|
|
ac.setSwingV(false);
|
|
EXPECT_EQ(false, ac.getSwingV());
|
|
|
|
ac.setSwingV(true);
|
|
EXPECT_TRUE(ac.getSwingV());
|
|
}
|
|
|
|
TEST(TestVoltasClass, SwingH) {
|
|
IRVoltas ac(kGpioUnused);
|
|
ac.begin();
|
|
// This model allows full control.
|
|
ac.setModel(voltas_ac_remote_model_t::kVoltasUnknown);
|
|
|
|
ac.setSwingHChange(false);
|
|
EXPECT_FALSE(ac.getSwingHChange());
|
|
|
|
ac.setSwingH(true);
|
|
EXPECT_TRUE(ac.getSwingH());
|
|
EXPECT_TRUE(ac.getSwingHChange());
|
|
|
|
ac.setSwingHChange(false);
|
|
ac.setSwingH(false);
|
|
EXPECT_FALSE(ac.getSwingH());
|
|
EXPECT_TRUE(ac.getSwingHChange());
|
|
|
|
ac.setSwingH(true);
|
|
EXPECT_TRUE(ac.getSwingH());
|
|
EXPECT_TRUE(ac.getSwingHChange());
|
|
|
|
// Switch to a model that does not allow SwingH control.
|
|
ac.setModel(voltas_ac_remote_model_t::kVoltas122LZF);
|
|
EXPECT_FALSE(ac.getSwingHChange());
|
|
EXPECT_FALSE(ac.getSwingH());
|
|
ac.setSwingH(true);
|
|
EXPECT_FALSE(ac.getSwingHChange());
|
|
EXPECT_FALSE(ac.getSwingH());
|
|
ac.setSwingH(false);
|
|
EXPECT_FALSE(ac.getSwingHChange());
|
|
EXPECT_FALSE(ac.getSwingH());
|
|
}
|
|
|
|
TEST(TestVoltasClass, HumanReadable) {
|
|
IRVoltas ac(kGpioUnused);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: Off, Mode: 8 (Cool), Temp: 23C, "
|
|
"Fan: 1 (High), Swing(V): Off, Swing(H): N/A, Turbo: Off, Econo: Off, "
|
|
"WiFi: Off, Light: Off, Sleep: Off, On Timer: Off, Off Timer: Off",
|
|
ac.toString());
|
|
ac.on();
|
|
ac.setTemp(21);
|
|
ac.setFan(kVoltasFanAuto);
|
|
ac.setSwingV(true);
|
|
ac.setWifi(true);
|
|
ac.setLight(true);
|
|
ac.setTurbo(true);
|
|
ac.setSleep(true);
|
|
ac.setEcono(true);
|
|
ac.setOnTime(2 * 60 + 17);
|
|
ac.setMode(kVoltasHeat); // Heat mode should cancel Sleep, Turbo, & Econo.
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 2 (Heat), Temp: 21C, "
|
|
"Fan: 7 (Auto), Swing(V): On, Swing(H): N/A, Turbo: Off, Econo: Off, "
|
|
"WiFi: On, Light: On, Sleep: Off, On Timer: 02:17, Off Timer: Off",
|
|
ac.toString());
|
|
ac.setOffTime(13 * 60 + 37);
|
|
ac.setMode(kVoltasCool);
|
|
ac.setTurbo(true);
|
|
ac.setSleep(true);
|
|
ac.setEcono(true);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 21C, "
|
|
"Fan: 7 (Auto), Swing(V): On, Swing(H): N/A, Turbo: On, Econo: On, "
|
|
"WiFi: On, Light: On, Sleep: On, On Timer: 02:17, Off Timer: 13:37",
|
|
ac.toString());
|
|
ac.setModel(voltas_ac_remote_model_t::kVoltasUnknown);
|
|
ac.setSwingH(true);
|
|
EXPECT_EQ(
|
|
"Model: 0 (UNKNOWN), Power: On, Mode: 8 (Cool), Temp: 21C, "
|
|
"Fan: 7 (Auto), Swing(V): On, Swing(H): On, Turbo: On, Econo: On, "
|
|
"WiFi: On, Light: On, Sleep: On, On Timer: 02:17, Off Timer: 13:37",
|
|
ac.toString());
|
|
ac.setModel(voltas_ac_remote_model_t::kVoltas122LZF);
|
|
ac.setOnTime(0);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 21C, "
|
|
"Fan: 7 (Auto), Swing(V): On, Swing(H): N/A, Turbo: On, Econo: On, "
|
|
"WiFi: On, Light: On, Sleep: On, On Timer: Off, Off Timer: 13:37",
|
|
ac.toString());
|
|
ac.setOffTime(0);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 21C, "
|
|
"Fan: 7 (Auto), Swing(V): On, Swing(H): N/A, Turbo: On, Econo: On, "
|
|
"WiFi: On, Light: On, Sleep: On, On Timer: Off, Off Timer: Off",
|
|
ac.toString());
|
|
}
|
|
|
|
TEST(TestVoltasClass, Timers) {
|
|
IRVoltas ac(kGpioUnused);
|
|
const uint8_t off_7hrs[10] = { // Real Data
|
|
0x33, 0x28, 0x80, 0x1B, 0x3B, 0x3B, 0x3B, 0x71, 0x40, 0xA7};
|
|
ac.setRaw(off_7hrs);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 27C, Fan: 1 (High), "
|
|
"Swing(V): Off, Swing(H): N/A, Turbo: Off, Econo: Off, WiFi: Off, "
|
|
"Light: Off, Sleep: Off, On Timer: Off, Off Timer: 06:59",
|
|
ac.toString());
|
|
const uint8_t off_16hrs[10] = { // Real Data
|
|
0x33, 0x28, 0x80, 0x1B, 0x3B, 0xBB, 0x3B, 0x41, 0x40, 0x57};
|
|
ac.setRaw(off_16hrs);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 27C, Fan: 1 (High), "
|
|
"Swing(V): Off, Swing(H): N/A, Turbo: Off, Econo: Off, WiFi: Off, "
|
|
"Light: Off, Sleep: Off, On Timer: Off, Off Timer: 15:59",
|
|
ac.toString());
|
|
ac.setOffTime(23 * 60 + 59);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 27C, Fan: 1 (High), "
|
|
"Swing(V): Off, Swing(H): N/A, Turbo: Off, Econo: Off, WiFi: Off, "
|
|
"Light: Off, Sleep: Off, On Timer: Off, Off Timer: 23:59",
|
|
ac.toString());
|
|
const uint8_t off_24hrs[10] = { // Real Data
|
|
0x33, 0x28, 0x80, 0x1B, 0x3A, 0x3A, 0x3B, 0x01, 0x40, 0x19};
|
|
ac.setRaw(off_24hrs);
|
|
EXPECT_EQ(
|
|
"Model: 1 (122LZF), Power: On, Mode: 8 (Cool), Temp: 27C, Fan: 1 (High), "
|
|
"Swing(V): Off, Swing(H): N/A, Turbo: Off, Econo: Off, WiFi: Off, "
|
|
"Light: Off, Sleep: Off, On Timer: Off, Off Timer: 23:58",
|
|
ac.toString());
|
|
}
|