Skip to content

Adding support for a new IR protocol

David Conran edited this page Sep 14, 2019 · 21 revisions

This is a quick guide of most of the steps required to add a new simple protocol to the library. This guide makes the assumption that the protocol is NOT larger than 64 bits.


Preparation

See if it is already supported first.

Take a look at the Supported Protocols document. See if we've already documented support for your Air Conditioner/Heat Pump. Obtain a IR Demodulator Hardware component, and build this circuit, and then compile and run the IRrecvDumpV2 example code on your ESP device. Monitor the serial output from the ESP module. The output should tell you what it knows about your protocol if it is supported, or list it as UNKNOWN if it doesn't know what it is.

Read the FAQ and first

See & read the FAQ.

Read the Writing Code Guide.

There are a number of automated checks that will not forgive incorrect or messy code. It may seem harsh, but it's there to help keep the library code readable. Code that doesn't pass won't be merged. Don't worry too much as help is given to first timers. :)

Is it an air conditioner/heat pump remote?

If it is, or the protocol is larger than 64 bits you probably want to follow these steps instead.

Obtain the make & model number of the controlled device AND the IR remote.

We will need that information later. Do some research to see if you can find any/all of the following:

  • The operation manual.
  • The specification for the IR protocol.
  • Links to any other implementations and projects that support your device and/or protocol.
  • Photos of the remote control etc.

For the purposes of this document, I'm going to assume the Device/Protocol is called "TestExample".


Obtaining the data.

Capture some "Raw" IR messages from the remote.

Use the circuit and program (IRrecvDumpV2) described above to capture a few simple messages from the remote.

  • Include the entire text of the output of the IRrecvDumpV2 program for the given messages. e.g. Including the timestamp, library version, and most importantly, the uint16_t rawData[] = {...}; line.

Use the auto_analyse_raw_data.py program.

Run the uint16_t rawData[] = {...}; output through the auto_analyse_raw_data.py program to examine and provide that output. It's a basic tool to do some rough analysis of the protocol and make some guesses to it's structure and parameters.

If you use the -g -n TestExample arguments to the program, it will give you some example code that can reproduce the IR message.

Log an issue (or fork your own repo/branch and send a PR) to add experimental support for the protocol.

Report all the information you've collected in a new issue. If you've got all that information, it can be likely fairly easily added to the library. That means, you can capture IR messages and they can be converted to a long, single hexidecimal code for your protocol via the auto_analyse_raw_data.py program, and you should be able to recreate the same signal using that hex code using the newly added sendTestExample() routine once the following is finished.


Modifying the library to add the ability to send messages

Is it a new vendor?

If there is already a file for the device under src/ir_*.cpp, you should add to that. If not, then copy a simple protocol (such as ir_Inax.cpp to src/ir_YourProtocol.cpp and use the generated code in place of the existing void IRsend::sendInax() routine. Do a search & replace and other obvious edits you may need to make it suit what you are adding.

Telling the library how many bits the protocol has.

Add const uint16_t kTestExampleBits = NN; where NN is the line the auto analyse tool told you it probably was to src/IRremoteESP8266.h

Create a new decode number for the protocol.

Search for kLastDecodeType. You will need to add your protocol name here to register it. e.g.

  DAIKIN152,  // 70
  MITSUBISHI136,
  // Add new entries before this one, and update it to point to the last entry.
  kLastDecodeType = MITSUBISHI136,
};

becomes

  DAIKIN152,  // 70
  MITSUBISHI136,
  TESTEXAMPLE,
  // Add new entries before this one, and update it to point to the last entry.
  kLastDecodeType = TESTEXAMPLE,
};

Keep the protocol name here UPPERCASE.

Enabling the sendTestExample() code.

Add the #define SEND_TESTEXAMPLE true to src/IRremoteESP8266.h in the appropriate place.

Adding a proto for the send function.

Add the following in the appropriate/obvious place:

#if SEND_TESTEXAMPLE
  void sendTestExample(const uint64_t data, const uint16_t nbits = kTestExampleBits,
                       const uint16_t repeat = kNoRepeat);
#endif  // SEND_TESTEXAMPLE

Update the IRsend::defaultBits() function

Add the number of bits to the uint16_t IRsend::defaultBits(const decode_type_t protocol) function in the obvious place.

Update the IRsend::send() function

Add to the 64 bit IRsend::send() function. i.e. bool IRsend::send(const decode_type_t type, const uint64_t data, const uint16_t nbits, const uint16_t repeat)

The following:

#if SEND_TESTEXAMPLE
    case TESTEXAMPLE:
      sendTestExample(data, nbits, min_repeat);
      break;
#endif  // SEND_TESTEXAMPLE

Please put it in alphabetical order to keep things nice. :)

Update the strToDecodeType() function.

In the appropriate alphabetical place add:

  else if (!strcasecmp(str, "TESTEXAMPLE"))
    return decode_type_t::TESTEXAMPLE;

Update the typeToString() function.

In the appropriate alphabetical place add:

    case TESTEXAMPLE:
      result = F("TESTEXAMPLE");
      break;

Update PROTOCOLS

Append ir_TestExample.o to the end of the PROTOCOLS = line(s). e.g.

    ir_Trotec.o ir_MitsubishiHeavy.o ir_Goodweather.o ir_Inax.o

becomes

    ir_Trotec.o ir_MitsubishiHeavy.o ir_Goodweather.o ir_Inax.o ir_TestExample.o

ir_TestExample.o

Append to the end of the file:

ir_TestExample.o : $(USER_DIR)/ir_TestExample.cpp $(COMMON_DEPS)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_TestExample.cpp

Congratulations! If everything went well you should now be able to compile and send using the IRsend::sendTestExample() procedure.


Optional advanced stuff

The exact same steps again as per test/Makefile

Unit tests

Create test/ir_TestExample_test.cpp

Copy test/ir_Inax_test.cpp to test/ir_TestExample_test.cpp and modify as needed to suit your new protocol. Remove any decoding sections if you haven't implemented that yet.

Add it to test/Makefile

Append to the end of the file:

ir_TestExample_test.o : ir_TestExample_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_TestExample_test.cpp

ir_TestExample_test : $(COMMON_OBJ) ir_TestExample_test.o
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

Update TESTS

Find the line(s)/section starting with TESTS = and append ir_TestExample_test to it. e.g.:

	ir_Inax_test ir_Neoclima_test ir_Amcor_test

becomes

	ir_Inax_test ir_Neoclima_test ir_Amcor_test ir_TestExample_test

Run the tests.

See the guide entry for that.

Modifying the library to add the ability to decode the messages

All the steps up to and including Create a new decode number for the protocol need to have been completed before you can perform these steps.

Enabling the sendTestExample() code.

Add #define DECODE_TESTEXAMPLE true to src/IRremoteESP8266.h in the appropriate place. i.e. Adjacent to SEND_TESTEXAMPLE.

Adding a proto for the decode function.

Add the following in the appropriate/obvious place in the private: section of class IRrecv:

#if DECODE_TESTEXAMPLE
  bool decodeTestExample(decode_results *results, const uint16_t nbits = kTestExampleBits,
                         const bool strict = true);
#endif  // DECODE_TESTEXAMPLE

ToDo: Add the rest of receive/decode etc.