Skip to content

Frequently Asked Questions

David Conran edited this page May 23, 2023 · 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.

Please help me configure HomeAssistant/ESPHome/Tasmota/ESPEasy/etc to work with your library etc.

Unless you're a code maintainer etc. of one of those projects (and we do really think those projects are wonderful, and we work with those teams frequently), No, we don't have the time nor effort to assist you. You should ask those teams & projects any configuration questions directly. We are are not experts in any of those projects, in fact, we don't use most of them, so you really are way way way better off asking them questions, not us. If you still feel the need to ask the questions here, please log them in the Discussions area; Please don't report them as an Issue.

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. Any ESP Arduino core version 2.4.2 or later should be fine.

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:

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?


  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 IRsend.h 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

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 (via

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 & ESP32-C3?

Yes. Support was added in v2.6.2. Support for ESP32-C3 was added in v2.8.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.
    The receiving end:
    // Use code similar to
      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");
    // Method 2: Handle the checksum yourself.
    char data_to_send[kHitachiAcStateLength] = "Hello World! Method 2";
    IRsend irsend(4);  // Send using GPIO 4.
    // Calculate & set the checksum.
    data_to_send[kHitachiAcStateLength - 1] = IRHitachiAC::calcChecksum(data_to_send);
    The receiving end:
    // Use code similar to
      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) {
    while (1) {
        unsigned long t1 = micros(), t2;
        irsend.sendSony(0x6666, 16, 2);
        t2 = micros();
        Serial.printf("round of ir takes %ld micros\n", (t2 - t1));        

void setup() {
        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 */

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.

Help, I'm getting very inconsistent results when capturing an IR message using a VS1838b IR demodulator!

Please have a read of this article and Issue#1173. It appears that the VS1838B is very cheap, and you get exactly what you pay for sometimes. In ideal conditions, you'll get good results, add sunlight/heat etc and it apparently offers poor perforce. We have had similar reports from our users. In short, buy a better hardware IR demodulation device, and your results should improve. If you can't afford the few extra cents, try some of the suggestions offered in Issue#1173.

I want to support a new device but all I have is an all-in-one, learning, or app-driven IR remote device for sending messages.

Generally we only add new protocols when the details are collected from an Original Remote for a given device. This is because we can (hopefully) trust the Original Equipment Manufacturer(OEM) to produce the correct signal and message format. Data collected from a generic/programable IR remote or phone app etc might have implemented the protocol incorrectly, thus we strongly prefer not using those sorts of things as the trusted source of data. While not frequent, we have seen bizarre behaviour from some of these devices and thus we don't want to trust them. Heck, this library gets protocols wrong from time to time too so we know it can happen. Just because the generic remote/app/program you have works on your device, it may not work on someone else's exact same hardware. The TL;DR: _Please_ only submit captured messages from an original IR remote.

How do I work out what protocol my remote uses?

  1. Start with looking at our list of supported devices. It may tell you what protocol and/or model code to use. If it doesn't list your exact model, try using the same Brand if available.
  2. Capture the IR messages using the IRrecvDumpV2 or V3 in the examples directory. If the library understands it, it should tell you what Protocol the messages are. You will need a hardware capture circuit in order to use it.
  3. If it is an A/C, try brute forcing it by using the CommonAcControl.ino example code. It will try to generate a `Power On` followed by a `Power Off` message for each A/C protocol that we have detailed support for. If you're A/C responds, you should be able to tell from the Serial output what Protocol it last tried. Note: This example code does NOT try each supported model in each protocol, only the default/first one.
Note that some Brands use another Brand's protocol. A/C's are often re-badged by other manufacturers. Midea has it's own protocol, but some of the devices it sells are controlled by the Coolix protocol. Many consumer electronic devices use the NEC protocol, but are not made by NEC. etc etc. If you find a device that is controlled by a Protocol, and it isn't in the list of supported devices, please create an issue to tell us the details, so we can add it.

This library doesn't work with my Arduino Uno/Leonardo/Nano/Micro/Mega/Duo/Zero/etc. Can you fix that?

No. Per the on the main page, this library is specifically designed for the ESP chip range. You're welcome to try to port it to those boards, but they have smaller memory, slower CPUs, and different features. Some of the sending routines should be trivial to port to the other libraries that are small enough to fit on those boards. e.g.

The IRac class (used by IRMQTTServer, Tasmota, etc) doesn't support a feature of my A/C. Why?

The IRac class is designed to be a generic interface to the common features for any/every Air Conditioner the library supports. It is not a generic interface to control every feature of an Air Conditioner. E.g. Timers, Additional Sensors, etc are not included. Some A/Cs have unusual or odd settings that are unique to them or only a few have it. If this is the case, it is unlikely to be supported. e.g. If an A/C has a special function to point the air output to where ever you are in the room, it's not going to be added. Not many A/Cs have a feature like that, hence it isn't common.

As the interface is a generic one, sometimes items don't exactly match what you would expect or hope for. For example, the generic Fan Speed only has 5 speeds (plus Auto), if your A/C has 6 or more speeds, then it tries to do it's best to match, but obviously it can't be perfect. Similarly, some A/Cs may only have 4 speeds, so one of the generic speeds will be the same as another. Similarly for Operation Modes, if your A/C doesn't have a Heat mode, it will probably default to Auto or Cool instead.

i.e. It can't and won't do everything it advertises it could possibly do, nor does it support every feature an A/C has.

If however, you think your A/C does support a generic option, and the IRac class behaves incorrectly, or not at all, please create & capture some data, report the issue, and we can try to work out how to control that setting & add support for it.

If you need finer, better, or more complete control of your A/C, you need to use your brand's individual class instead of the generic IRac interface. e.g. Samsung. These individual classes provide all the support the library currently has for the device in question.

I'm using the Async webserver library and some IR protocols don't seem to send correctly. Why?

You should not make an IR irsend.sendBlah() or ac_class.send() call from inside an async callback routine (or an interrupt handler for that matter). By default, our library makes use of delay() calls when sending IR messages. Libraries like ESPAsyncWebServer etc do not allow or work well with delay() or yield() calls. The solutions are to:

  • Move any IR calls out of the callback; (Best) or
  • Use an alternative non-Async library.; or
  • Set ALLOW_DELAY_CALLS to false which will remove all delay() calls from our library.
If you don't make these changes, some of the longer pauses in an IR message won't be made, thus the message will be malformed. This typically is most often encounter when sending repeats, or some AC protocols that have long gaps in them, and a few other quirky protocols. At worst, your ESP will crash or behave oddly in other functions.

What libraries are known to be incompatible with this library?

  • Ticker [ESP8266]
    The IRrecv & Ticker classes both use the same single hardware timer on the ESP8266. Thus, both can't be enabled at the same time. Sending IR messages is fine however.
    The ESP32 has 4 hardware timers, hence this isn't a problem on that platform.
    See Issue #1533.
  • ESPAsyncWebServer
    You can't send IR messages correctly from a callback in that library by default. ESPAsyncWebServer does not allow or work well with delay() or yield() calls which this library uses.
    You can modify our library to work with their library by setting ALLOW_DELAY_CALLS to false which will remove all delay() calls from our library.
    Note: That is far from optimal. You should instead move all IR send calls out of callback functions. IR messages can take 100's of milliseconds to send. Not allowing the ESPs RTOS to use those delay()s may cause other issues. e.g. WDT resets.

I am getting the occasional corrupted IR message captures when using GPIO 36 or 39 when using WiFi on an ESP32?

This is a known hardware issue. The workaround is to add this to you code:

#include "driver/adc.h"

void setup()

See Issue #1995 for more context and details.

Clone this wiki locally