Skip to content

Commit

Permalink
IRMQTTServer: Fix bug when receiving an A/C message and not re-transm…
Browse files Browse the repository at this point in the history
…itting it. (#1038)

* When an incoming IR A/C message changed the state, we didn't always update the previous state once it was dealt with.
* Misc. code style & typo fixes.
* Version bump.
* Extra unit tests used along the way.

Fixes #1035
  • Loading branch information
crankyoldgit authored Feb 6, 2020
1 parent 9248222 commit 0fc8379
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 17 deletions.
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);
}

0 comments on commit 0fc8379

Please sign in to comment.