Skip to content

Frequently Asked Questions

David Conran edited this page Mar 6, 2020 · 48 revisions

Frequently Asked (and answered) Questions.

Here is a list of questions that seem to get repeated often enough to make it onto this list. Your question may be already answered here.

Table of Contents

Help. All I'm getting on the Serial Monitor is stuff like ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮%⸮⸮⸮⸮⸮!⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮ʭ⸮ĭ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮ when I run the example code.

You most likely have a baud rate mismatch. All of our example code uses a serial baud rate of 115200 8-N-1. Please set your terminal/serial monitor to that speed and you should be fine.

I want to change the example code to make it do something different, but I don't know how. Please help me.

Please don't ask us how to program in Arduino/C/C++/HTML/etc. We don't have time for that. There are many (free) resources out there. If you want to program and can't - there are always plenty of tutorials, books, and forums for you to learn from available by just a quick Google search.

The examples won't compile. It gives an error about the max() function.

If you get an error message similar to:

ir_JVC.cpp: In member function 'void IRsend::sendJVC(uint64_t, uint16_t, uint16_t)':

C:\Users\REDACTED\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.0.0\cores\esp8266/Arduino.h:253:18: error: expected unqualified-id before '(' token

#define max(a,b) ((a)>(b)?(a):(b))
Chances are you are using an old version of the Arduino core for ESP8266 WiFi chip. You should upgrade to the latest version, which is currently 2.4.2.


Try following these instructions to install it correctly. Once installed correctly, you should go to Arduino -> Tools -> Board -> Boards Manager... -> (Search for 'esp8266'), click on the esp8266 entry, click [Update]

It is highly unlikely there is a simple compilation error in the unaltered library & examples. Every change to the library & examples gets tested & checked on Travis. If you have a compilation error, it is much more likely something is wrong with your personal Arduino build environment.

I'm getting "error: 'IRsend' does not name a type" messages.

Your code or the project you are using hasn't updated properly from V1.X to V2.X of the library. Please follow the upgrade instructions.

Can I use this library with an ESP-01 module?

Yes you can, however we don't provide much support for it. We don't recommend doing it if you're new to ESP8266 modules, or as your first IRremoteESP8266 project. There is a dire shortage of GPIO pins on the ESP-01 module. The ones that are exposed are commonly used for Serial Commons (RxD/TxD) or are used to control firmware updating, or boot mode. If you have to use one of these modules, we recommend not performing ANY serial I/O and use either of the RxD/TxD GPIOs or use limit serial usage to transmitting only (e.g. Debugging) by initialising the serial comms with SERIAL_TX_ONLY thus freeing the RX/GPIO3 pin for use. e.g.

Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
Note: You will have to remove the module from the IR LED/Receiver circuit to program it.

You will save yourself a lot of hassles by paying the extra couple of dollars and get a NodeMCU or Wemos D1 mini dev board instead.

See also: https://github.com/crankyoldgit/IRremoteESP8266/issues/7#issuecomment-360837185

Sending an Sony IR Code doesn't work, my device doesn't respond.

Sony devices need to see an IR code sent at least 3 times in order to act on it. More than 3 times simulates the button on the remote being held for longer. To simulate a button press the minimum required is:

sendSony(code, bitLength, 2);  // Initial code + 2 repeats.
As of v2.0 of the library, sendSony() defaults to 2 repeats (sending a code 3 times).

The library/example code doesn't understand my Air Conditioner remote ...

Air Conditioner IR signals are typically very complex and vary a lot even from the same manufacturer. The example code, and the library itself evolved from handling simple IR protocols. e.g. TV remotes. Compare support for sending & decoding Nikai TV codes (approx 120 lines of code) with the send-only Kelvinator A/C support (approx 480 lines of code). Adding Nikai TV support only took a few hours with no access to the device, and only a couple of message captures. Where as adding Kelvinator support took weeks of effort, access to the devices, and almost 100 different message captures. Simple IR device protocols use a 12-48 bit value mapping a single button press. A/C remotes however tend to send the entire state of the remote to the device with each button press. e.g. Desired Temp., Operating Mode, Fan Speed, Fan Direction(s), Economy Mode(s), Sleep Modes, Time & Timer Modes, etc, plus a checksum. In short, imagine it sending every button on the remote for each button press. This can produce a message of around 128 bits of data, which is often broken in half and sent as two messages back-to-back. If you want to use this library to control your air-conditioner unit, you have several options (in order of increasing difficulty):

  1. Use IRrecvDumpV2 example code to capture a raw dump of the data and try sending it back with the sendRaw() method. You may need to tweak the kTimeout value accordingly depending on your device, as a lot of A/C remote messages are split over multiple closely sent messages. Change the kTimeout value to a larger value may allow the program to capture those multiple messages as a single raw message which you can replay. If you are really lucky, this can take you as little as a few minutes of effort. Expect a couple of hours though.
  2. Find another Arduino-based project that has already solved/decoded your particular device, and let us know. Most of the hard work is in understanding and decoding the signal, so it can be re-constructed. If there is a need, and available code, it doesn't take too much to convince us to add support for your device. e.g. Mitsubishi A/C support. If you are lucky, this may take only a several hours, to a couple of days or so to add support.
  3. You capture about 30-50 codes (that you can successfully replay like in the first step) varying only one bit of information on the remote at a time; trying to isolate each function; store them in a spreadsheet, and spend some quality time trying to map what each bit of the message means. Once you get to that point, you can probably either copy & modify an existing A/C module to code it yourself, or present us with that information, and we can probably do the rest of it for you. Decoding the messages you should expect to take several hours to days depending on the complexity, it is the bulk of the work and often the hardest part. Wrapping that up in code can take a couple to several days of effort too.

My remote's signal is being reported as an "Unknown" code. What does that mean? How do I send an Unknown code?

The decode() method will try to make up a synthetic unique data value for what ever message it received even though it doesn't understand it. The code value is a result of a non-invertible hash function. It is a last-resort attempt to allow you to potentially match the same message when it is sent later. As the value is a non-invertible hash, it is useless for reproducing the message. The bit count is also a synthetic value; it is just a count of how many high-to-low transitions it detected. Don't rely on these values at all.

In order to reproduce the message, you are going to have to use the rawData, for example as captured by the IRrecvDumpV2 sketch. You send the raw data using the sendRaw() method as per example code. Please note that the library can't tell what frequency the captured message was transmitted at. You'll have to make an educated guess when using sendRaw(). The most common frequency used is 38kHz. That would be where you should probably start, or use the receiving frequency of the IR receiving module you are using. You can look through the various src/ir_*.cpp files for lines like enableIROut(38) or sendGeneric() to give yourself an idea of commonly used frequencies, if that doesn't work.

If you want to look at adding support for your protocol to the library, consider taking these steps.

Occasionally I'm getting seemingly random & unwanted UNKNOWN values, is there a way to get rid of them?

Yes.

  1. If you are only interested in detecting signals from protocols supported by the library, you can disable it from reporting signals it doesn't understand. i.e. UNKNOWNs. To disable them completely, set DECODE_HASH to false in IRremoteESP8266.h.
  2. If you still want to detect some unknown/unexpected signals but just want to reduce the occurrence of false-detection, you can also set a higher threshold for how long a message has to be before it will consider reporting it as UNKNOWN. You can do this by using the setUnknownThreshold(length) call. Where length is the minimum total number of on/off pulses required in a message before it is reported as unknown.
  3. Otherwise you can try reducing the default kTimeoutMs value or use a lower timeout parameter when you initialise the IRrecv class. That will reduce how long the library will listen before it gives up looking for a message. Less time listening means less chance of picking up random IR signal noise which is what is probably causing the unwanted/unexpected UNKNOWNs in the first place.
    Note: Setting this value too low will break detection of protocols.

I'm getting some random odd values (< 50 usecs) in my capture of an IR message. What is up with that?

There are a number of possibilities for that. e.g. Random IR noise, electrical interference, poor quality hardware IR receiver module. However, the most likely cause is a mismatch between the frequency modulation of the incoming signal and that of the hardware receiver module. e.g. The remote is sending with a modulation of 36kHz or 40kHz and the receiving hardware is designed for 38kHz. This is a hardware issue, not a software issue.

The good news is, it mostly works. You can often get good readings on short messages, but the longer the message the more likely you are going to get one of these errors/mismatches. You can try to hand edit the captures to massage-out bad pulse readings and adjust neighbouring ones. Sometimes that will work.

38kHz is by far the most common modulation for most devices, and the most common hardware IR receiver frequency. Just don't assume that every remote transmits at 38kHz. The good news is, different freq. IR modules are cheaply available and the library can send at almost any frequency modulation.

These too short pulses can sometimes appear when you hold the remote too close to the receiver. Try with a greater separation. e.g. >= 1 Meter.

I'm noticing a slight transmission frequency modulation mismatch. What can I do to fix it?

As the Frequency Modulation (PWM signal) is done in software, there can be subtle influences in instruction timing that cause a slight different freq. result than the one requested. The code handles that with a pre-calculated offset (see kPeriodOffset in [../blob/master/src/IRsend.h#L25] to adjust it's timings. As the ESP8266 chips can vary, the number of instructions used for sending depending on the library operation, and the clock frequency can be changed, there is a method to re-calibrate this value for your specific situation. It however comes at the cost of a one-off ~65ms long series of pulses to the IR LED. This probably isn't a problem in most circumstances, but it could be in some situations, thus it is not used by default. Use at your own discretion.

In order to invoke this self-calibration, add a call to the calibrate(freq) function in IRsend class. This only needs to be done once. i.e. Typically in the setup() function and after the irsend.begin() call. The calibrate() call defaults to 38kHz as the frequency you are most likely to be using, but you can change that if needed. It will calculate a new period offset, which in theory should be good for all realistic transmission frequencies, regardless of what freq. the calibrate() function is called with.

Note: As this is a software-only implementation of PWM, the precision is limited to integer micro-second precision. e.g. 26us, not 26.3157us (The period of a true 38000Hz frequency) You won't get an absolutely precise frequency output from this library. A period of 26us (38461.63Hz) is good enough for most devices.

Some of the examples don't produce output that I expect and I have to use a baud rate of 74880. What's up?

It looks like you have a "bad" esp8266 board. e.g. Read all of this issue thread https://github.com/esp8266/Arduino/issues/4005

The TL;DR: is if you have to use a baud rate of 74880 then it's likely a bad module or the module needs to be wiped fully. The clock/crystal on it may be wrong and it won't work for wifi etc. All the timings are off.

I don't want to recommend specific vendors etc, but I've had great luck with purchasing NodeMCU and Wemos D1 mini modules via Aliexpress or ebay. The official wemos store is https://www.aliexpress.com/store/1331105 (via http://www.wemos.cc/)

Alternatively you can try using another computer and/or the steps listed here which helped at least one user fix their problem.

Does this library work on the ESP32?

Yes. Support was added in v2.6.2.

Why is the raw data for a button or A/C state always different for each capture?

Raw messages are a representation of an analogue message.

i.e. If I taped someone Italian saying "Buon giorno", and played it back to you. You might think I spoke Italian. But the same person who I recorded could say it again, and it would be slightly different no matter how hard they tried. That's what sendRaw() does, it's like a .wav recording. It's a digital encoding of the analogue signal. I'd also be unable to say anything else in Italian. I'd be like a talking parrot.

The next level the library has, if the base protocol is supported is to effectively convert the sounds to text. i.e. .wav to .txt. Much smaller. Similarly, the library essentially converts the raw format into a short state[]/integer format. It can then also convert the text to speech, if we follow the same metaphor. However, it's now digital, so it will always produce the same output to the speaker. It doesn't understand the message, it just know how to covert sounds to letters, and vice versa.

The final level, if supported, is to understand what the text means. eg. grammar, and how to construct a sentence, to be fluent. To know that "Buon giorno" means "Good Morning". That is, to convert the state[]/integer into various AirCon settings, and vice versa.

Why is IRMQTTServer very slow? It takes a while to respond. What's wrong?

If you have MQTT_ENABLE set to true then this is typically because your ESP is not correctly connecting to your MQTT broker. Check the "Info" html page on the ESP to see if it is connecting okay. If you need to change the MQTT settings, you will need to "Wipe Settings" to get back the setup menu. If you are not going to use MQTT, then you should change MQTT_ENABLE to false, recompile, and upload the new firmware binary.

Can you reverse engineer my AirCon protocol for me?

TL;DR: No.

As mentioned earlier in the FAQ, breaking down an AirCon message into its component settings and controls (This process is referred to as Reverse Engineering) is an intensive effort and quite time consuming.

There are documents describing how you can do this yourself. See Adding a new IR protocol & Adding a new AC protocol

I don't expect everyone to know how program C++ well, or be able to use git & Github. You are using/writing Arduino code, which is C++ so you know at least some. Most people have enough brain power to work the problem of finding which bytes and bits inside a protocol controls are associated to their actions. It's not too hard, it just requires time and effort. If you look at the data, you easily can see patterns in what changes. If you can use a spreadsheet, or a pencil & paper then you should be able to do it eventually.

Thus, I offer/assist with the coding stages of adding a new protocol (provided you assist with data collection), but my skills are not always needed for the analysis/reverse engineering phase. In fact, because I don't have access to your remote and Air Conditioner, it's actually harder for me to do it than for you. As you have access to it, you can try/use different settings to see what changes. I can't.

I'll answer questions or help if you get stuck on something tricky. However, as I have done so many protocol reverse engineering for this library already, & I have no vested interest in controlling your specific A/C brand and model. I no longer feel the need to do this for other people in my free time. The coding and support I already freely offer amounts to typically 8-16 hours of programming per protocol. In exchange for my time, I expect you to put in some effort too. i.e. The Analysis. That phase can take about the same amount of time too.

So, no. I will not deconstruct the A/C protocol for you. I will help you do it, but if you don't put in any effort, don't expect me to.

Can I send arbitrary data with this library? e.g. ASCII text.

Short answer: No. This library does not offer any easy or simple interface to send arbitrary chunks of data from one device to another via IR.

Long answer: Yes. It sort-of can, but you will have do some coding work on your own to do it.

There are several ways you can transmit arbitrary data using this library, but the library is not designed to do that. The library is based around emulating existing known protocols used by various micro-controllers and consumer devices.

So, your options are:

  1. (Easy) Send only a few bytes at a time. i.e. Co-opt an existing simple IR protocol. A lot of IR protocols have some internal structures and checks to ensure corrupt messages are ignored. You will have to choose a protocol that has limited checks and the payload is big enough to send the amount of data you want to send in a single message.
    • Sending 32 bits of data: Use IRsend::sendWhynter() will let you send arbitrary data i.e. no check bits or patterns.

      Alternatively, the most common/abused protocol is NEC. IRsend::sendNEC() will let you also send 32 bits of data, but it will be detected as one of two protocols depending on the payload. NEC has a specific bit/check pattern, if the payload follows that pattern it will be detected as NEC, if it doesn't it will be detected as NEC_LIKE. i.e. You will have to check that the protocol to see if it is either NEC or NEC_LIKE.

    • Sending 48 bits of data: IRsend::sendGoodweather().

      Not as fast, but more data (48 bits). It duplicates the message by sending an inverted copy a byte for every byte it sends. So, more reliable, but at least twice as long a message.

    Suggestions only.
    The sending end:
    uint64_t data = 0x1234567890AB;
    IRsend irsend(4);  // Send using GPIO 4.
    irsend.begin();
    irsend.sendGoodweather(data);
    The receiving end:
    // Use code similar to https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRrecvDemo/IRrecvDemo.ino
      if (irrecv.decode(&results)) {
        if (results.decode_type == decode_type_t::GOODWEATHER) {  // Did we get an Goodweather message?
          // print() & println() can't handle printing long longs. (uint64_t)
          serialPrintUint64(results.value, HEX);  // // We did. So print the integer in Hexidecimal.
        }
        irrecv.resume();  // Receive the next IR message.
      }
  2. (Moderate) Send a "short string's worth" of data at a time. i.e. Co-opt an Air-Conditioner message.

    Most air-conditioner IR messages are quite long. They often use an array of bytes as the message to be sent. However, as they are quite long, they often have specific byte signatures or elaborate checks in them to ensure nothing has corrupted the message during transmission.

    Currently the longest A/C message that has a known single check value at the end of the message is IRsend::sendHitachiAC(). You could use it to send a uint8_t data[kHitachiAcStateLength] array. That's 28 bytes in total including the checksum byte. So 27 usable bytes. 26 usable bytes if you are using a null-terminated string. To calculate the checksum use the IRHitachiAC class object, or you need to do it yourself.

    Suggestions only.
    The sending end:

    // Send a short (sub-27 byte string).
    
    // Method 1: Use the IRHitachiAC object.
    IRHitachiAC ac(4);  // Send using GPIO 4.
    ac.setRaw("Hello World! Method 1");
    ac.send();
    
    // Method 2: Handle the checksum yourself.
    char data_to_send[kHitachiAcStateLength] = "Hello World! Method 2";
    IRsend irsend(4);  // Send using GPIO 4.
    irsend.begin();
    // Calculate & set the checksum.
    data_to_send[kHitachiAcStateLength - 1] = IRHitachiAC::calcChecksum(data_to_send);
    irsend.sendHitachiAC(data_to_send);
    The receiving end:
    // Use code similar to https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRrecvDemo/IRrecvDemo.ino
      if (irrecv.decode(&results)) {
        if (results.decode_type == decode_type_t::HITACHI_AC) {  // Did we get an HitachiAC message?
          Serial.println(results.state);  // We did. So print the text.
        }
        irrecv.resume();  // Receive next IR message.
      }
  3. (Hard) Design & write your own IR protocol sender and decoder.

    I'm not going to go into this here & now, but it's not going to be easy. In short, take a look at an existing A/C protocol and adapt what you need. If you need help, just lodge an issue.

Some other library (e.g. Bluetooth) is interfering with 'IRsend'! What can I do? [ESP32]

See Issue #1031 for more details.

It's likely that the other library is interrupting the sensitive timing required by the IRsend class/object.

An easy way to potentially work around this is to run the IRsend functions on the second (1) CPU, and leave what ever is interfering with it to run on the first (0) CPU.

e.g. (Kudos to @playrobotics-alex)

TaskHandle_t send_ir_task;
IRsend irsend(18);

void send_ir_f(void *param) {
    irsend.begin();
    delay(100);
    while (1) {
        unsigned long t1 = micros(), t2;
        irsend.sendSony(0x6666, 16, 2);
        delay(100);
        t2 = micros();
        Serial.printf("round of ir takes %ld micros\n", (t2 - t1));        
    }
}


void setup() {
    ... 
    xTaskCreatePinnedToCore(
        send_ir_f,     /* Task function. */
        "Send IR code",    /* name of task. */
        2000,           /* Stack size of task */
        NULL,           /* parameter of the task */
        1,              /* priority of the task */
        &send_ir_task, /* Task handle to keep track of created task */
        1); 
    ...
}

P.S. No help will be give on converting your code to use Tasks like this. That is far beyond the scope of this library. Some alternative suggestions are suggested in #1031, feel free to try those too.

My Arduino Uno etc. detects protocols fine, but doesn't on an ESP8266/ESP32. What's wrong?

or "IRrecvDumpV2 appears to work fine on my Uno, but when I run it on my ESP device, it gets UNKNOWN`s all the time."

A lot of the standard Arduino devices use 5 Volts(V). The ESP's all use 3.3V. A commonly reported issue happens when someone is using a hardware IR receiving module that requires to be powered at 5V. Powering it with 3.3V causes weird operation. i.e. It can't detect IR properly. The solution is to use an IR receiver module that operates fine at 3.3V (preferred), or (See warning below first) to power the module's Vcc pin from a 5V source. i.e. Typically the board's Vin pin if you are powering your ESP board via USB.

The ESP8266 has 5V-tolerant I/O pins. So, it should handle the IR receiver module operating at 5V.

WARNING: The ESP32's I/O pins are not 5V-tolerant! You could damage your ESP32.
If you interface the board with 5V (or higher) components, you'll need to do some level shifting first.

Does this library support multiple distinct IR capture sources?

No. It only supports a single IR signal source in order to reduce IRAM/ICACHE_FLASH_ATTR and memory usage. IRAM is a very limited resource on the ESP8266. It is used by Interrupt routines, which the IR receiving routines are.

You can however, connect multiple hardware IR demodulator units together in a circuit, and use them via a single input GPIO on your ESP, and it will typically work. However, you will not be able tell which IR demodulator received the signal.