ESP32 IR Blaster Troubleshooting: Range and AC Commands

Fix ESP32 IR blaster range, missed commands and air-conditioner control problems. Covers LED drivers, carrier frequency, raw captures, ESPHome climate IR, AC state frames and practical diagnostics.

If an ESP32 IR blaster works only from 20 cm away, controls the TV but not the air conditioner, or sends an AC command that beeps without changing the setting, the problem is usually hardware strength, placement or protocol handling rather than Home Assistant itself.

Simple TV remotes often send a short command such as “Power” or “Volume Up”. Air-conditioner remotes are much more complicated: many transmit the entire AC state in one long infrared message, including power, operating mode, target temperature, fan speed, swing and sometimes timer or feature bits. Replaying the wrong state frame can therefore look like a successful IR transmission while producing the wrong result.

This guide starts with the physical IR transmitter because weak output is the most common failure, then moves through ESPHome configuration, learning codes, carrier frequency, repeats and AC-specific troubleshooting.

Quick Diagnosis: What Your Symptom Usually Means

SymptomMost likely first check
Works only from a few centimetresIR LED current, transistor driver, LED orientation and aiming
Works on TV but not ACAC protocol/state frame, carrier frequency and message length
AC beeps but setting does not changeWrong model/protocol variant or incomplete state frame
Captured raw code works once but not reliablyBad capture, insufficient buffer, timing variation or missing repeats
Home Assistant shows AC on when it is offIR is one-way unless receiver tracking is supported
Some commands work only when LED is directly in frontWeak optical output or poor LED beam angle
Nothing responds but YAML compilesLED polarity, GPIO, driver wiring and carrier modulation
Original remote is detected but replay failsTransmitter hardware or incorrect protocol/raw format

Start with the Hardware: Do Not Drive a Powerful IR LED Directly

An ESP32 GPIO can generate the timing signal, but it should not be expected to supply the current for a strong IR transmitter. A high-output IR LED is normally driven through an NPN transistor or logic-level MOSFET.

A simple NPN arrangement is:

Supply
  |
current-limiting resistor
  |
IR LED anode
IR LED cathode
  |
collector
NPN transistor
emitter
  |
 GND

ESP32 GPIO -- base resistor -- transistor base

ESP32 GND ------------------ common GND

The exact LED resistor should be calculated from the supply voltage, LED forward voltage and intended pulse current rather than copied blindly from another project:

R ≈ (Vsupply - VIR_LED - Vdriver) / ILED

Infrared LEDs can often tolerate a higher pulsed current than their continuous rating, but only within the limits in the LED datasheet. The 38 kHz carrier does not give permission to overdrive an unknown LED. If you do not know the part specification, use a conservative current.

Why a Transistor Improves Range

IR range depends heavily on optical power. If the GPIO directly supplies only a small LED current, the receiver may work at close range but fail across a room. A transistor lets the ESP32 control a stronger current from the power rail without asking the GPIO itself to source it.

That is why the classic failure pattern is:

5 cm      works
50 cm     intermittent
2 metres  fails

If moving the blaster closer immediately fixes the problem, debug the transmitter strength and optics before changing protocol timings.

Check IR LED Polarity

An IR LED is still a diode. Reverse it and it will not transmit useful infrared light. On a loose through-hole LED, the longer lead is normally the anode and the flat edge of the package usually marks the cathode, but verify the actual part if possible.

The easiest practical test is a phone camera. Many cameras can see near-infrared as a pale purple or white flash. Some modern phones have strong IR-blocking filters, particularly on the main rear camera, so a blank camera image does not prove the LED is dead. Try the front camera or another device before concluding the hardware has failed.

Beam Angle Matters as Much as Current

Two IR LEDs with the same electrical rating can behave very differently. A narrow-angle LED concentrates more optical power straight ahead and can achieve impressive distance, but only when aimed accurately. A wide-angle LED covers more of the room but spreads its energy over a larger area.

For a wall-mounted AC controller, a narrow or medium-angle LED aimed at the indoor unit is normally ideal. For a universal living-room blaster trying to reach a TV, soundbar and set-top box in different directions, two or more LEDs at different angles can be more useful.

If you use multiple LEDs, give each LED an appropriate current-limiting path. Do not simply parallel mismatched LEDs behind one resistor and assume the current will divide equally.

ESPHome Remote Transmitter Setup

A normal ESPHome IR transmitter starts with:

remote_transmitter:
  pin: GPIO19
  carrier_duty_percent: 50%

ESPHome currently recommends around 50% carrier duty for ordinary IR LEDs. Its newer infrared proxy documentation describes roughly 30–50% as a normal infrared range. Do not use the 100% setting intended for unmodulated RF transmitters.

ESP32 is a good platform for this job because most ESP32 variants use dedicated RMT hardware for accurate transmit timing. That removes a major timing burden from application code.

Carrier Frequency: Usually 38 kHz, but Not Always

Most consumer IR equipment uses a carrier close to 38 kHz. The remote does not simply turn the LED on for the duration of each logical pulse; it rapidly modulates the LED at the carrier frequency during each “mark”. The appliance’s receiver is tuned to that modulation.

If ESPHome sends a known protocol action, the protocol implementation normally handles the appropriate carrier. For raw transmission you can specify it explicitly:

button:
  - platform: template
    name: "Raw IR Test"
    on_press:
      - remote_transmitter.transmit_raw:
          carrier_frequency: 38kHz
          code: [9000, -4500, 560, -560, 560, -1690]

A wrong carrier frequency can reduce range dramatically even when the visible timing pattern looks correct. Some protocols use carriers other than 38 kHz, so do not force 38 kHz merely because it is common if the protocol documentation says otherwise.

Learn the Original Remote Before Guessing

If you are troubleshooting an unknown appliance, add an IR receiver and capture the original remote. Our ESP32 IR Receiver for Home Assistant guide covers the full learning setup.

A simple receiver configuration is:

remote_receiver:
  pin:
    number: GPIO23
    inverted: true
    mode:
      input: true
      pullup: true

  dump: all
  tolerance: 25%
  filter: 50us
  idle: 10ms

Use a demodulating receiver intended for the remote’s carrier, such as a 38 kHz TSOP-style receiver for common consumer remotes. The receiver removes the carrier and gives the ESP32 the mark/space envelope.

Prefer Decoded Protocol Data over Raw Timings

If ESPHome recognises the protocol, use the decoded representation when practical. A protocol action is easier to maintain and less sensitive to minor timing variations than a long copied raw list.

Raw dumps naturally vary slightly between button presses because real remotes, receivers and clocks are not perfect. A pulse captured as 560 µs once might appear as 548 or 574 µs on another press. That does not mean the remote sent a different logical command.

For unknown devices, raw replay is still extremely useful. Capture the same command several times and compare the shape. If every capture is radically different in length or timing, fix the receiver setup before building automations around one questionable recording.

Why Air-Conditioner Commands Are Different

A TV remote commonly sends a command such as:

POWER
VOLUME_UP
INPUT

Many AC remotes instead maintain an internal state. When you press temperature up, the remote changes its internal setpoint and then sends a complete message similar to:

Power = ON
Mode = COOL
Temperature = 24 C
Fan = AUTO
Vertical swing = ON
Horizontal swing = OFF
Turbo = OFF
Timer = OFF
Checksum = ...

This is why an AC capture can contain dozens or hundreds of timing entries. It is also why treating one recording as a generic “temperature up” command is often wrong. The recording may really mean “Cool, 24°C, Auto Fan, Swing On”.

The IRremoteESP8266 project’s AC abstraction follows this same model: its common AC state contains power, mode, degrees, fan and swing information before the protocol-specific library creates the transmitted frame.

Use ESPHome IR Climate When Your AC Is Supported

For a supported air conditioner, the best solution is usually ESPHome’s IR Remote Climate component rather than a collection of raw buttons. ESPHome currently has native climate platforms for many protocols and brands including Daikin, Fujitsu General, Gree, Hitachi, LG, Midea, Mitsubishi, Toshiba, Whirlpool and others. It also supports the Arduino-HeatpumpIR library as a wider fallback for additional models.

A supported climate component lets Home Assistant present a proper thermostat-style entity with mode, setpoint and fan controls. The component constructs the full IR state message for you.

For example:

remote_transmitter:
  pin: GPIO19
  carrier_duty_percent: 50%

climate:
  - platform: mitsubishi
    name: "Bedroom AC"
    supports_cool: true
    supports_heat: true

The exact options depend on the protocol. Our ESP32 AC Climate Controller for Home Assistant guide covers the complete setup.

Why Home Assistant Can Show the Wrong AC State

Infrared is usually one-way. The ESP32 sends a command but the AC does not normally acknowledge it over IR. ESPHome therefore documents IR climate state as assumed state: Home Assistant remembers what it last requested, not necessarily what the appliance is currently doing.

State can become wrong when:

  • Someone uses the original remote.
  • The IR transmission misses the receiver.
  • The wrong protocol/model variant is selected.
  • The AC rejects an unsupported state combination.

Some ESPHome climate protocols support a receiver_id. In that case an optional IR receiver can listen to the original remote and update the ESPHome climate state. Check the current support table for your protocol rather than assuming every brand can do this.

Raw AC Replay: Capture Complete Useful States

If your AC protocol is not supported, raw replay can still work extremely well. Instead of trying to capture abstract commands such as “Temp +”, capture useful complete states:

Home Assistant buttonState sent by original remote
AC OffPower off
Cool 23Cool, 23°C, Auto fan
Cool 24Cool, 24°C, Auto fan
Cool 25Cool, 25°C, Auto fan
Heat 21Heat, 21°C, Auto fan
Heat 22Heat, 22°C, Auto fan
DryDry mode with desired fan/swing settings

This is less elegant than a native climate entity, but it is predictable. Each button represents one known complete AC state.

Long AC Frames Can Overflow a Receiver Configuration

Air-conditioner frames are often much longer than TV commands. If the log shows truncated raw sequences, buffer warnings or incomplete decodes, increase the receiver capacity rather than trusting the partial capture.

Current ESPHome uses the ESP32 RMT peripheral on variants that support it. The available RMT receive memory differs by chip—for example classic ESP32 has more receive-symbol capacity than some C3/C6 variants by default. ESPHome exposes settings such as rmt_symbols, receive_symbols and DMA where supported.

If a short TV command captures correctly but a long AC command is consistently cut off, this is a strong clue that the receiver configuration—not the AC protocol itself—is the problem.

Raw Timing Tolerance

When decoding, ESPHome applies timing tolerance because real pulses are not exact. If a protocol is almost recognised but not consistently, a slightly wider tolerance can help. Do not immediately push tolerance to an extreme value; that can also make unrelated noise look valid.

For learning an unknown remote, start with sensible defaults and compare multiple captures. A good raw capture should show a repeatable overall pattern even when individual durations differ slightly.

Repeat Count: More Is Not Always Better

Some simple IR protocols expect repeated frames while a remote button is held. ESPHome transmit actions support repeats for protocols where they are useful.

Do not solve every unreliable command by transmitting it five or ten times. For a toggle command, repeating the wrong frame can sometimes produce unexpected behaviour. For an AC full-state frame, one correctly transmitted complete state is usually more important than brute-force repetition.

If a command works only when repeated, first check optical power and protocol details. Repeats should reproduce the remote’s normal behaviour, not hide a weak transmitter.

Why the AC Beeps but Does Not Change State

A beep proves only that the indoor unit detected something it considered recognisable. It does not prove the whole command was correct.

Common reasons include:

  • Correct brand but wrong protocol variant.
  • Correct protocol but wrong remote/model number.
  • Incomplete long frame.
  • Incorrect checksum after manually modifying a captured frame.
  • Unsupported mode or fan combination.
  • Weak IR where only part of a multi-frame command is received.

If the ESPHome native platform has a model option, try the documented model variants systematically. Do not assume every appliance with the same badge uses the same protocol generation.

Protocol Libraries Are Better Than Editing AC Bytes by Hand

Many AC formats contain checksums, complements or multiple blocks. Changing one byte representing temperature may require another byte to change as well. The IRremoteESP8266 project documents this exact reverse-engineering process when adding AC protocols.

If your AC is supported by ESPHome or a mature IR library, use the protocol implementation. Manually editing a raw byte sequence should be a last resort for unsupported hardware.

A Known-Good ESPHome IR Test

Before debugging an AC, prove the transmitter with a simple known remote protocol or a captured TV command:

remote_transmitter:
  pin: GPIO19
  carrier_duty_percent: 50%

button:
  - platform: template
    name: "IR Test"
    on_press:
      - remote_transmitter.transmit_raw:
          carrier_frequency: 38kHz
          code:
            - 4088
            - -1542
            - 1019
            - -510
            - 513
            - -1019

The timings above are only an abbreviated example, not a universal remote command. Replace them with a complete known-good capture from your device. ESPHome’s official setup guide uses the same raw timing convention: positive durations are IR marks and negative durations are spaces.

Test the Blaster in Stages

A reliable troubleshooting sequence is:

  1. Confirm the original remote still controls the appliance from the same position.
  2. Check the ESP32 IR LED flashes with a camera.
  3. Test the blaster at 10–20 cm from the receiver window.
  4. Move to 1 metre.
  5. Test from the intended mounting location.
  6. Only then add Home Assistant automations and scenes.

If it works perfectly at 20 cm but not at 3 metres, stop changing YAML. You have already proved the protocol is close enough; improve the optical transmitter.

Finding the AC Receiver Window

The receiver is not always centred on the indoor unit. It is normally behind a small dark plastic window near the display or indicator LEDs. Use the original remote as a probe: cover portions of the front panel or change your angle until you determine where reception becomes strongest.

Mount the ESP32 blaster so the IR LED has a clear optical path to that location. Infrared can reflect from light-coloured walls, but a direct path is much more reliable for permanent automation.

Sunlight and Other IR Noise

Strong sunlight can reduce the sensitivity of an IR receiver because it contains significant infrared energy. If the system works at night but becomes unreliable in direct afternoon sun, do not immediately blame ESPHome.

Move the blaster closer, improve aiming or shield the appliance receiver from direct sunlight if practical. Fluorescent lighting and some LED lighting can also create optical interference, although modern demodulating receivers are designed to reject much of it.

The IR Receiver Can Interfere with Your Own Transmissions

If the same ESP32 has both an IR transmitter and receiver, the receiver may see the blaster’s own IR output. This is useful for diagnostics but can also flood logs or trigger automations unexpectedly.

Do not point the receiver directly at the transmitter LED. If you use received codes to trigger actions, design the automation so your own transmitted command cannot create a loop.

Troubleshooting ESPHome IR Climate

ProblemWhat to try
Climate entity appears but AC does nothingVerify transmitter hardware, GPIO, LED direction and exact AC protocol/model.
Power works but temperature does notCheck protocol/model variant and supported temperature range.
Cooling works but heating does notConfirm the appliance actually supports heat and check platform-specific options.
Fan choices do not match remoteProtocol abstraction may expose only a subset or use different model settings.
Home Assistant state becomes wrongAdd receiver tracking if the platform supports it or accept assumed-state behaviour.
Unit reacts only at close rangeFix IR LED driver/placement before changing the climate platform.
One brand platform partly worksTry the documented model/protocol variants for the actual remote model.

Troubleshooting Raw IR Replay

ProblemWhat to try
Raw code never worksVerify full capture, carrier frequency, polarity convention and transmitter strength.
Works only occasionallyCapture multiple samples and compare; test stronger IR output.
AC capture is truncatedIncrease receiver/RMT capacity or adjust idle timing.
One state works, another failsRecapture the complete failed state; do not modify only the visible temperature bytes.
Command toggles unexpectedlyCheck whether the protocol uses a toggle bit or repeated frame semantics.
Replay controls another device tooUse protocol-specific addressing where possible rather than a generic raw command.

When to Use IRremoteESP8266

For Arduino projects or unsupported ACs, the IRremoteESP8266 library remains extremely useful. Its AC support includes a common IRac interface plus protocol-specific classes for detailed control. Its supported-protocol list includes many air-conditioner families and model variants.

A typical workflow is:

  • Use an IR receiver to identify the protocol.
  • Check whether that protocol has detailed AC support.
  • Set power, mode, temperature, fan and swing in the library’s state object.
  • Let the library generate checksums and protocol-specific frames.

For an ESPHome project, use the native climate platform first where available. ESPHome also exposes the Arduino-HeatpumpIR option for many additional AC units when the native platforms do not cover a model.

ESPHome’s New IR/RF Proxy Is Different

ESPHome now also has an experimental IR/RF Proxy and infrared API that can pass raw timing sequences between an ESPHome device and API clients such as Home Assistant. This is useful for universal-remote style development, but ESPHome currently labels the component experimental, meaning its API may still change.

For a stable dedicated AC controller today, the established remote_transmitter plus an IR climate platform is still the straightforward route.

Recommended Hardware for Reliable Room-Scale Range

For a permanent ESP32 IR controller, I would use:

  • An ESP32 with hardware RMT support.
  • One or two known IR LEDs with documented electrical ratings.
  • An NPN transistor or logic-level MOSFET LED driver.
  • A correctly calculated series resistor for each LED path.
  • A stable power supply with common ground.
  • A 38 kHz demodulating IR receiver for learning common remotes.
  • Direct line-of-sight placement toward the appliance.

That hardware is cheap, but it solves far more reliability problems than trying to compensate for a weak directly driven LED in software.

Recommended Troubleshooting Order

When an IR blaster is unreliable, work through the layers in this order:

  1. Power: verify the ESP32 and LED-driver supply.
  2. LED: verify polarity and camera-visible flashing.
  3. Driver: verify transistor/MOSFET wiring and current-limiting resistor.
  4. Placement: test from 10 cm and then increase distance.
  5. Carrier: confirm protocol/carrier frequency.
  6. Capture: compare several original-remote recordings.
  7. Protocol: prefer decoded/native protocol support.
  8. AC state: confirm full-state/model behaviour.
  9. Home Assistant: only add scenes and automations after local transmission is reliable.

This sequence prevents a common mistake: spending an hour editing YAML when the IR LED is simply too weak or pointed in the wrong direction.

Related ESP32 IR Guides

External Resources

Share your love