Skip to content

Adding support for a new IR protocol

David Conran edited this page Oct 24, 2020 · 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. However, it can apply for protocols with >64 bits too.


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 will probably want to follow these steps after doing these steps.

Obtain the make & model number of the controlled device AND the original 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.

Please only submit data collected from the original IR remote. Not a clone/generic/app/learning I remote etc. See the FAQ on this topic as to why. Generally, data from a third-party remote will not be accepted.

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 original remote.

Use the circuit and program (IRrecvDumpV2) described above to capture a few simple messages from the original remote. No third-party remotes please.

  • 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 & parameters. If you use the -g -n TestExample arguments to the program, it will give you some example code that can reproduce & decode the IR message. Please note that the code it generates may or may not work, or even compile. It's a starting point only. No promises are given!

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.

Add the string name of your new protocol.

Add the text string name of the protocol. In the appropriate alphabetical place add:

#ifndef D_STR_TESTEXAMPLE
#define D_STR_TESTEXAMPLE "TESTEXAMPLE"
#endif  // D_STR_TESTEXAMPLE

e.g. https://github.com/crankyoldgit/IRremoteESP8266/blob/f4ed9bc9dff38ce3813f93c2a371e6034bb8e3a9/src/locale/defaults.h#L454-L456

Add the your new protocol string to the list of protocol names (kAllProtocolNamesStr). You need to keep this list in the same order as the decode protocol numbers. i.e. Add to the bottom of the list.

    D_STR_AIRWELL "\x0"
    D_STR_TESTEXAMPLE "\x0"
    // New protocol strings should be added just above this line.
    "\x0";  // This string requires double null termination.

e.g. https://github.com/crankyoldgit/IRremoteESP8266/blob/f4ed9bc9dff38ce3813f93c2a371e6034bb8e3a9/src/IRtext.cpp#L249-L251

Update the hasACState() function.

You need to do this step if and only if the protocol you are adding uses the results->state[] method of storing the protocol message. e.g. When you message is >= 64 bits. If not, you can safely skip this step.

Basically, if it does, you need to add the following line in the correct alphabetical spot: case TESTEXAMPLE: This just lets the library know to use results->state[] rather than results->value for the protocol.

Adding a proto for the send function.

Add the following in the appropriate/obvious place; for =< 64 bit protocols:

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

for > 64 bit protocols:

#if SEND_TESTEXAMPLE
  void sendTestExample(const unsigned char data[],
                       const uint16_t nbytes = kTestExampleStateLength,
                       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

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

<= 64 bits

Add to the uint64_t data version of the 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

> 64 bits

Add to the uint8_t state[] version of the IRsend::send() function. i.e. bool IRsend::send(const decode_type_t type, const unsigned char *state, const uint16_t nbytes)

The following:

#if SEND_TESTEXAMPLE
    case TESTEXAMPLE:
      sendTestExample(state, nbytes);
      break;
#endif  // SEND_TESTEXAMPLE

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


Optional advanced stuff

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.

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 Edit IRutils.cpp need to have been completed before you can perform these steps.

Enabling the decodeTestExample() 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,
                         uint16_t offset = kStartOffset,
                         const uint16_t nbits = kTestExampleBits,
                         const bool strict = true);
#endif  // DECODE_TESTEXAMPLE

e.g. https://github.com/crankyoldgit/IRremoteESP8266/blob/f4ed9bc9dff38ce3813f93c2a371e6034bb8e3a9/src/IRrecv.h#L591-L595

Updating IRrecv::decode.

You need to add your new decodeTestExample() function to the main IRrecv::decode() function. Search for this line:

// Typically new protocols are added above this line.

and add in your decoder so it looks like:

#if DECODE_TESTEXAMPLE
  DPRINTLN("Attempting TestExample decode");
  if (decodeTestExample(results)) return true;
#endif  // DECODE_TESTEXAMPLE
  // Typically new protocols are added above this line.

Update the hasACState() function.

You need to do this step if and only if the protocol you are adding uses the results->state[] method of storing the protocol message. e.g. When you message is >= 64 bits. If not, you can safely skip this step.

Basically, if it does, you need to add the following line in the correct alphabetical spot: case TESTEXAMPLE: This just lets the library know to use results->state[] rather than results->value for the protocol.


Congratulations! If everything went well you should now be able to compile and decode using the IRrecv::decode() function.


Clone this wiki locally