Skip to content

Commit

Permalink
Added support for Gorenje cooker hood IR protocol (#1888)
Browse files Browse the repository at this point in the history
Closes: #1887
```
// Supports:
//   Brand: Gorenje,  Model: DKF 2600 MWT Cooker Hood
```
See [here](https://github.com/mbronk/IRremoteESP8266/blob/416798dd5ae2ced324dade0972111bc79a7eb504/test/ir_Gorenje_test.cpp#L120) for raw data examples.

_Cheers!
-Mateusz_

Signed-off-by: Mateusz Bronk [email protected]
  • Loading branch information
mbronk authored Sep 27, 2022
1 parent 726b219 commit 71cd956
Show file tree
Hide file tree
Showing 9 changed files with 308 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Daikin 312-bit decode");
if (decodeDaikin312(results, offset)) return true;
#endif // DECODE_DAIKIN312
#if DECODE_GORENJE
DPRINTLN("Attempting GORENJE decode");
if (decodeGorenje(results, offset)) return true;
#endif // DECODE_GORENJE
// Typically new protocols are added above this line.
}
#if DECODE_HASH
Expand Down
5 changes: 5 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ class IRrecv {
const uint16_t nbits = kGoodweatherBits,
const bool strict = true);
#endif // DECODE_GOODWEATHER
#if DECODE_GORENJE
bool decodeGorenje(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kGorenjeBits,
const bool strict = true);
#endif // DECODE_GORENJE
#if DECODE_GREE
bool decodeGree(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kGreeBits,
Expand Down
11 changes: 10 additions & 1 deletion src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,13 @@
#define SEND_DAIKIN312 _IR_ENABLE_DEFAULT_
#endif // SEND_DAIKIN312

#ifndef DECODE_GORENJE
#define DECODE_GORENJE _IR_ENABLE_DEFAULT_
#endif // DECODE_GORENJE
#ifndef SEND_GORENJE
#define SEND_GORENJE _IR_ENABLE_DEFAULT_
#endif // SEND_GORENJE

#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
Expand Down Expand Up @@ -1104,8 +1111,9 @@ enum decode_type_t {
BOSCH144, // 120
SANYO_AC152,
DAIKIN312,
GORENJE,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = DAIKIN312,
kLastDecodeType = GORENJE,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1203,6 +1211,7 @@ const uint16_t kGicableBits = 16;
const uint16_t kGicableMinRepeat = kSingleRepeat;
const uint16_t kGoodweatherBits = 48;
const uint16_t kGoodweatherMinRepeat = kNoRepeat;
const uint16_t kGorenjeBits = 8;
const uint16_t kGreeStateLength = 8;
const uint16_t kGreeBits = kGreeStateLength * 8;
const uint16_t kGreeDefaultRepeat = kNoRepeat;
Expand Down
6 changes: 6 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) {
uint16_t IRsend::defaultBits(const decode_type_t protocol) {
switch (protocol) {
case MULTIBRACKETS:
case GORENJE:
return 8;
case RC5:
case SYMPHONY:
Expand Down Expand Up @@ -916,6 +917,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendGoodweather(data, nbits, min_repeat);
break;
#endif
#if SEND_GORENJE
case GORENJE:
sendGorenje(data, nbits, min_repeat);
break;
#endif
#if SEND_GREE
case GREE:
sendGree(data, nbits, min_repeat);
Expand Down
4 changes: 4 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,10 @@ class IRsend {
const uint16_t nbits = kGoodweatherBits,
const uint16_t repeat = kGoodweatherMinRepeat);
#endif // SEND_GOODWEATHER
#if SEND_GORENJE
void sendGorenje(const uint64_t data, const uint16_t nbits = kGorenjeBits,
const uint16_t repeat = kNoRepeat);
#endif // SEND_GORENJE
#if SEND_PRONTO
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,8 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_SANYO_AC152, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_DAIKIN312 || SEND_DAIKIN312,
D_STR_DAIKIN312, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_GORENJE || SEND_GORENJE,
D_STR_GORENJE, D_STR_UNSUPPORTED) "\x0"
///< New protocol (macro) strings should be added just above this line.
"\x0" ///< This string requires double null termination.
};
Expand Down
71 changes: 71 additions & 0 deletions src/ir_Gorenje.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2022 Mateusz Bronk (mbronk)
/// @file
/// @brief Support for the Gorenje cooker hood IR protocols.
/// @see https://techfresh.pl/wp-content/uploads/2017/08/Gorenje-DKF-2600-MWT.pdf
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1887

// Supports:
// Brand: Gorenje, Model: DKF 2600 MWT Cooker Hood

#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"

const uint32_t kGorenjeMinGap = 100000U; // 0.1s
const uint16_t kGorenjeHdrMark = 0;
const uint32_t kGorenjeHdrSpace = 0;
const uint16_t kGorenjeBitMark = 1300;
const uint32_t kGorenjeOneSpace = 5700;
const uint32_t kGorenjeZeroSpace = 1700;
const uint16_t kGorenjeFreq = 38000; // Hz
const uint16_t kGorenjeTolerance = 7; // %

#if SEND_GORENJE
/// Send a Gorenje Cooker Hood formatted message.
/// Status: STABLE / Known working.
/// @param[in] data containing the IR command to be sent.
/// @param[in] nbits Nr. of bits of the message to send. usually kGorenjeBits
/// @param[in] repeat Nr. of times the message is to be repeated.
void IRsend::sendGorenje(const uint64_t data, const uint16_t nbits,
const uint16_t repeat) {
sendGeneric(kGorenjeHdrMark, kGorenjeHdrSpace,
kGorenjeBitMark, kGorenjeOneSpace,
kGorenjeBitMark, kGorenjeZeroSpace,
kGorenjeBitMark, kGorenjeMinGap,
data, nbits, kGorenjeFreq, true, repeat, kDutyDefault);
}
#endif // SEND_GORENJE

#if DECODE_GORENJE
/// Decode the supplied Gorenje Cooker Hood message.
/// Status: STABLE / Known working.
/// @param[in,out] results Ptr to the data to decode & where to store the
/// decoded result
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
/// @return A boolean. True if it can decode it, false if it can't.
bool IRrecv::decodeGorenje(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kGorenjeBits)
return false; // We expect Gorenje to be a certain sized message.

uint64_t data = 0;
if (!matchGeneric(results->rawbuf + offset, &data,
results->rawlen - offset, nbits,
kGorenjeHdrMark, kGorenjeHdrSpace,
kGorenjeBitMark, kGorenjeOneSpace,
kGorenjeBitMark, kGorenjeZeroSpace,
kGorenjeBitMark, kGorenjeMinGap,
true, kGorenjeTolerance)) return false;

// Matched!
results->bits = nbits;
results->value = data;
results->decode_type = decode_type_t::GORENJE;
results->command = 0;
results->address = 0;
return true;
}
#endif // DECODE_GORENJE
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_GOODWEATHER
#define D_STR_GOODWEATHER "GOODWEATHER"
#endif // D_STR_GOODWEATHER
#ifndef D_STR_GORENJE
#define D_STR_GORENJE "GORENJE"
#endif // D_STR_GORENJE
#ifndef D_STR_GREE
#define D_STR_GREE "GREE"
#endif // D_STR_GREE
Expand Down
203 changes: 203 additions & 0 deletions test/ir_Gorenje_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Copyright 2022 Mateusz Bronk (mbronk)

#include "IRac.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"

class TestDecodeGorenjeSyntheticSendTestFixture
: public ::testing::TestWithParam<uint64_t> {};
class TestDecodeGorenjeReceiveTestFixture
: public ::testing::TestWithParam<std::tuple<std::vector<uint16_t>,
uint64_t>> {};

TEST(TestGorenje, Settings) {
ASSERT_EQ("GORENJE", typeToString(decode_type_t::GORENJE));
ASSERT_EQ(decode_type_t::GORENJE, strToDecodeType("GORENJE"));
ASSERT_FALSE(hasACState(decode_type_t::GORENJE));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::GORENJE));
ASSERT_EQ(kGorenjeBits,
IRsendTest::defaultBits(decode_type_t::GORENJE));
}

// Test sending typical data (cooker hood light toggle)
TEST(TestSendGorenje, SendLightToggle) {
IRsendTest irsend(kGpioUnused);
irsend.begin();

irsend.reset();
irsend.sendGorenje(0x10); // Light toggle
EXPECT_EQ(
"f38000d50"
"m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000",
irsend.outputStr());
}

// Test sending with different repeats.
TEST(TestSendGorenje, SendWithRepeats) {
IRsendTest irsend(kGpioUnused);
irsend.begin();

irsend.reset();
irsend.sendGorenje(0x8, kGorenjeBits, 0); // 0 repeats.
EXPECT_EQ(
"f38000d50"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000",
irsend.outputStr());
irsend.sendGorenje(0x8, kGorenjeBits, 2); // 2 repeats.
EXPECT_EQ(
"f38000d50"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000",
irsend.outputStr());
}


// Decode a Synthetic example
TEST_P(TestDecodeGorenjeSyntheticSendTestFixture, SyntheticExample) {
uint64_t commandToTest = GetParam();
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

irsend.reset();
irsend.sendGorenje(commandToTest);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(GORENJE, irsend.capture.decode_type);
EXPECT_EQ(kGorenjeBits, irsend.capture.bits);
EXPECT_EQ(commandToTest, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}

INSTANTIATE_TEST_CASE_P(
TestDecodeGorenje,
TestDecodeGorenjeSyntheticSendTestFixture,
::testing::Values(0x2, 0x8, 0x4, 0x10, 0x20, 0x1));


// Decode a real example (codes captured from original remote)
TEST_P(TestDecodeGorenjeReceiveTestFixture, RealExample) {
const std::vector<uint16_t> rawDataInput = std::get<0>(GetParam());
const uint64_t expectedValue = std::get<1>(GetParam());

IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

irsend.reset();
irsend.sendRaw(&rawDataInput[0], rawDataInput.size(), 38000);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::GORENJE, irsend.capture.decode_type);
EXPECT_EQ(kGorenjeBits, irsend.capture.bits);
EXPECT_EQ(expectedValue, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}

INSTANTIATE_TEST_CASE_P(
TestDecodeGorenje,
TestDecodeGorenjeReceiveTestFixture,
::testing::Values(
// POWER
std::make_tuple(std::vector<uint16_t> {
1292, 1716, 1300, 1708, 1296, 1712,
1294, 1714, 1302, 1708, 1298, 1710,
1294, 5752, 1294, 1714, 1302
},
0x2),
std::make_tuple(std::vector<uint16_t> {
1302, 1706, 1298, 1710, 1294, 1714,
1292, 1716, 1300, 1708, 1296, 1712,
1294, 5754, 1292, 1716, 1300
},
0x2),

// FAN-
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1324, 1684, 1320, 1688,
1328, 1680, 1324, 5724, 1322, 1684,
1330, 1678, 1326, 1682, 1324
},
0x8),
std::make_tuple(std::vector<uint16_t> {
1296, 1712, 1292, 1718, 1298, 1710,
1294, 1714, 1292, 5756, 1300, 1708,
1296, 1712, 1294, 1714, 1300
},
0x8),

// FAN+
std::make_tuple(std::vector<uint16_t> {
1324, 1684, 1320, 1688, 1328, 1680,
1324, 1684, 1322, 1688, 1328, 5718,
1326, 1682, 1322, 1686, 1352
},
0x4),
std::make_tuple(std::vector<uint16_t> {
1296, 1714, 1292, 1716, 1298, 1710,
1296, 1714, 1292, 1716, 1300, 5748,
1296, 1712, 1292, 1716, 1300
},
0x4),

// Light toggle
std::make_tuple(std::vector<uint16_t> {
1326, 1682, 1322, 1686, 1328, 1680,
1324, 5722, 1322, 1686, 1330, 1680,
1326, 1682, 1322, 1686, 1328
},
0x10),
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1324, 1684, 1330, 1678,
1326, 5722, 1324, 1684, 1330, 1678,
1326, 1682, 1322, 1686, 1330
},
0x10),

// Light-
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1324, 1686, 1330, 5716,
1328, 1680, 1324, 1684, 1330, 1678,
1326, 1682, 1354, 1654, 1328
},
0x20),
std::make_tuple(std::vector<uint16_t> {
1322, 1686, 1318, 1690, 1326, 5722,
1322, 1686, 1330, 1678, 1326, 1682,
1322, 1686, 1328, 1680, 1324
},
0x20),

// Light+
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1326, 1682, 1322, 1688,
1328, 1680, 1324, 1686, 1330, 1678,
1326, 1682, 1322, 5724, 1330
},
0x1),
std::make_tuple(std::vector<uint16_t> {
1298, 1710, 1294, 1714, 1302, 1708,
1298, 1710, 1294, 1716, 1300, 1708,
1296, 1712, 1292, 5756, 1300
},
0x1)
)
);

0 comments on commit 71cd956

Please sign in to comment.