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

IRMQTTServer: Fix bug when receiving an A/C message and not re-transmitting it. #1038

Merged
merged 11 commits into from
Feb 6, 2020
2 changes: 1 addition & 1 deletion examples/IRMQTTServer/IRMQTTServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ const uint16_t kJsonAcStateMaxSize = 1024; // Bytes
// ----------------- End of User Configuration Section -------------------------

// Constants
#define _MY_VERSION_ "v1.4.5"
#define _MY_VERSION_ "v1.4.6"

const uint8_t kRebootTime = 15; // Seconds
const uint8_t kQuickDisplayTime = 2; // Seconds
Expand Down
26 changes: 15 additions & 11 deletions examples/IRMQTTServer/IRMQTTServer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -2679,7 +2679,7 @@ uint64_t getUInt64fromHex(char const *str) {
// code: Numeric payload of the IR message. Most protocols use this.
// code_str: The unparsed code to be sent. Used by complex protocol encodings.
// bits: Nr. of bits in the protocol. 0 means use the protocol's default.
// repeat: Nr. of times the message is to be repeated. (Not all protcols.)
// repeat: Nr. of times the message is to be repeated. (Not all protocols.)
// Returns:
// bool: Successfully sent or not.
bool sendIRCode(IRsend *irsend, decode_type_t const ir_type,
Expand Down Expand Up @@ -3071,6 +3071,10 @@ bool sendClimate(const String topic_prefix, const bool retain,
lastClimateIr.reset();
irClimateCounter++;
}
// Mark the "next" value as old/previous.
if (ac != NULL) {
ac->markAsSent();
}
return success;
}

Expand Down Expand Up @@ -3098,20 +3102,20 @@ bool decodeCommonAc(const decode_results *decode) {
}
#if IGNORE_DECODED_AC_PROTOCOL
if (climate[0]->next.protocol != decode_type_t::UNKNOWN) {
// Use the previous protcol/model if set.
// Use the previous protocol/model if set.
state.protocol = climate[0]->next.protocol;
state.model = climate[0]->next.model;
}
#endif // IGNORE_DECODED_AC_PROTOCOL
// Continue to use the previously prefered temperature units.
// i.e. Keep using Celsius or Fahrenheit.
if (climate[0]->next.celsius != state.celsius) {
// We've got a mismatch, so we need to convert.
state.degrees = climate[0]->next.celsius ? fahrenheitToCelsius(state.degrees)
: celsiusToFahrenheit(state.degrees);
state.celsius = climate[0]->next.celsius;
}
climate[0]->next = state; // Copy over the new climate state.
// Continue to use the previously prefered temperature units.
// i.e. Keep using Celsius or Fahrenheit.
if (climate[0]->next.celsius != state.celsius) {
// We've got a mismatch, so we need to convert.
state.degrees = climate[0]->next.celsius ?
fahrenheitToCelsius(state.degrees) : celsiusToFahrenheit(state.degrees);
state.celsius = climate[0]->next.celsius;
}
climate[0]->next = state; // Copy over the new climate state.
#if MQTT_ENABLE
sendClimate(genStatTopic(0), true, false, REPLAY_DECODED_AC_MESSAGE,
REPLAY_DECODED_AC_MESSAGE, climate[0]);
Expand Down
2 changes: 1 addition & 1 deletion examples/IRrecvDumpV2/IRrecvDumpV2.ino
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* Version 0.4 July, 2018
* - Minor improvements and more A/C unit support.
* Version 0.3 November, 2017
* - Support for A/C decoding for some protcols.
* - Support for A/C decoding for some protocols.
* Version 0.2 April, 2017
* - Decode from a copy of the data so we can start capturing faster thus
* reduce the likelihood of miscaptures.
Expand Down
9 changes: 7 additions & 2 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ IRac::IRac(const uint16_t pin, const bool inverted, const bool use_modulation) {
_inverted = inverted;
_modulation = use_modulation;
initState(&next);
_prev = next;
this->markAsSent();
}

void IRac::initState(stdAc::state_t *state,
Expand Down Expand Up @@ -1628,13 +1628,18 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
return true; // Success.
}

// Update the previous state to the current one.
void IRac::markAsSent(void) {
_prev = next;
}

// Send an A/C message based soley on our internal state.
//
// Returns:
// boolean: True, if accepted/converted/attempted. False, if unsupported.
bool IRac::sendAc(void) {
bool success = this->sendAc(next, &_prev);
_prev = next;
if (success) this->markAsSent();
return success;
}

Expand Down
1 change: 1 addition & 0 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class IRac {
const bool beep, const int16_t sleep,
const int16_t clock);
static void initState(stdAc::state_t *state);
void markAsSent(void);
bool sendAc(void);
bool sendAc(const stdAc::state_t desired, const stdAc::state_t *prev = NULL);
bool sendAc(const decode_type_t vendor, const int16_t model,
Expand Down
2 changes: 1 addition & 1 deletion src/ir_Midea.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void IRsend::sendMidea(uint64_t data, uint16_t nbits, uint16_t repeat) {
enableIROut(38);

for (uint16_t r = 0; r <= repeat; r++) {
// The protcol sends the message, then follows up with an entirely
// The protocol sends the message, then follows up with an entirely
// inverted payload.
for (size_t inner_loop = 0; inner_loop < 2; inner_loop++) {
// Header
Expand Down
2 changes: 1 addition & 1 deletion src/ir_Sanyo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ uint64_t IRsend::encodeSanyoLC7461(uint16_t address, uint8_t command) {
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp
// http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf
void IRsend::sendSanyoLC7461(uint64_t data, uint16_t nbits, uint16_t repeat) {
// This protocol appears to be another 42-bit variant of the NEC protcol.
// This protocol appears to be another 42-bit variant of the NEC protocol.
sendNEC(data, nbits, repeat);
}
#endif // SEND_SANYO
Expand Down
61 changes: 61 additions & 0 deletions test/IRac_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1600,3 +1600,64 @@ TEST(TestIRac, Issue1001) {
"Command: 1 (Power)",
IRAcUtils::resultAcToString(&ac._irsend.capture));
}

// Check power switching in Daikin2 common a/c handling when from an IR message.
TEST(TestIRac, Issue1035) {
stdAc::state_t prev; // Previously desired state
stdAc::state_t result; // State we need to send to get to `desired`
prev.protocol = decode_type_t::DAIKIN2;
prev.model = -1;
prev.power = false;
prev.mode = stdAc::opmode_t::kAuto;
prev.degrees = 24;
prev.celsius = true;
prev.fanspeed = stdAc::fanspeed_t::kAuto;
prev.swingv = stdAc::swingv_t::kOff;
prev.swingh = stdAc::swingh_t::kOff;
prev.quiet = false;
prev.turbo = false;
prev.econo = false;
prev.light = false;
prev.filter = false;
prev.clean = false;
prev.beep = false;
prev.sleep = -1;

// https://github.com/crankyoldgit/IRremoteESP8266/issues/1035#issuecomment-580963572
const uint8_t on_code[kDaikin2StateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x01, 0x15, 0x43, 0x90, 0x29, 0x0C, 0x80, 0x04,
0xC0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xC1, 0x2D, 0x11, 0xDA, 0x27, 0x00,
0x00, 0x09, 0x2A, 0x00, 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1,
0x90, 0x60, 0x0C};
const uint8_t off_code[kDaikin2StateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x01, 0x15, 0xC3, 0x90, 0x29, 0x0C, 0x80, 0x04,
0xC0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD1, 0xBD, 0x11, 0xDA, 0x27, 0x00,
0x00, 0x08, 0x2A, 0x00, 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1,
0x90, 0x60, 0x0B};

IRac irac(kGpioUnused);
IRrecv capture(kGpioUnused);
IRDaikin2 ac(kGpioUnused);

ac.begin();
ac.setRaw(on_code);
ac.send();
ac._irsend.makeDecodeResult();
ASSERT_TRUE(capture.decode(&ac._irsend.capture));
ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
ASSERT_FALSE(prev.power);
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev));
ASSERT_TRUE(result.power);

prev = result;

ac._irsend.reset();
ac.setRaw(off_code);
ac.send();
ac._irsend.makeDecodeResult();
ASSERT_TRUE(capture.decode(&ac._irsend.capture));
ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
ASSERT_TRUE(prev.power);
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev));
ASSERT_FALSE(result.power);
}
36 changes: 36 additions & 0 deletions test/ir_Daikin_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3364,3 +3364,39 @@ TEST(TestDaikin152Class, BuildKnownState) {
0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x6F};
EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikin152Bits);
}

TEST(TestDaikin2Class, Issue1035) {
IRDaikin2 ac(kGpioUnused);
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1035#issuecomment-580963572
const uint8_t on_code[kDaikin2StateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x01, 0x15, 0x43, 0x90, 0x29, 0x0C, 0x80, 0x04,
0xC0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xC1, 0x2D, 0x11, 0xDA, 0x27, 0x00,
0x00, 0x09, 0x2A, 0x00, 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1,
0x90, 0x60, 0x0C};
const uint8_t off_code[kDaikin2StateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x01, 0x15, 0xC3, 0x90, 0x29, 0x0C, 0x80, 0x04,
0xC0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD1, 0xBD, 0x11, 0xDA, 0x27, 0x00,
0x00, 0x08, 0x2A, 0x00, 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1,
0x90, 0x60, 0x0B};

ac.setRaw(on_code);
EXPECT_EQ(
"Power: On, Mode: 0 (Auto), Temp: 21C, Fan: 11 (Quiet), "
"Swing(V): 1 (Highest), Swing(H): 190 (Auto), Clock: 13:09, "
"On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 2 (Loud), "
"Light: 1 (High), Mould: On, Clean: On, Fresh: On, Eye: Off, "
"Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off",
ac.toString());
ASSERT_TRUE(ac.toCommon().power);
ASSERT_NE(ac.toCommon().mode, stdAc::opmode_t::kOff);

ac.setRaw(off_code);
EXPECT_EQ(
"Power: Off, Mode: 0 (Auto), Temp: 21C, Fan: 11 (Quiet), "
"Swing(V): 1 (Highest), Swing(H): 190 (Auto), Clock: 13:09, "
"On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 2 (Loud), "
"Light: 1 (High), Mould: On, Clean: On, Fresh: On, Eye: Off, "
"Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off",
ac.toString());
ASSERT_FALSE(ac.toCommon().power);
}