Skip to content

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

IRremoteIDF

CI Lint Docs Component Registry

Send and receive infrared (IR) signals from ESP-IDF.

This is an ESP-IDF port of IRremoteESP8266 v2.9.0. Every protocol decoder, encoder and air-conditioner state class is carried over unchanged, so the protocol behaviour is identical — the same 1669 unit tests from upstream run against this code and pass. What was rewritten is the layer underneath: the Arduino core dependency is gone, replaced by native ESP-IDF GPIO, esp_timer and (optionally) LEDC.

  • 130 protocols, most of them both send and decode.
  • Full climate control for 60+ A/C brands via the vendor-neutral IRac class — mode, temperature, fan, swing, quiet, turbo, econo, sleep, clock.
  • No Arduino compatibility layer to install. It is a plain ESP-IDF component with a Kconfig, a manifest and nothing else.
  • Builds on ESP32, ESP32-S2/S3, ESP32-C2/C3/C5/C6, ESP32-H2 and ESP32-P4.

Install

From the ESP Component Registry

idf.py add-dependency "jorgecis/IRremoteIDF^1.0.2"

As a git submodule

git submodule add https://github.com/jorgecis/IRremoteIDF.git \
    components/IRremoteIDF

Either way, no further CMake changes are needed. Include the headers and go:

#include "IRsend.h"

static IRsend irsend(4);  // GPIO driving the IR LED.

extern "C" void app_main(void) {
  irsend.begin();
  irsend.sendNEC(0x00FFE01FUL);
}

Hardware

Function Typical part Notes
Receive TSOP38238, VS1838B, TSOP4838 38 kHz demodulator. Output straight to a GPIO.
Transmit 940 nm IR LED + NPN/MOSFET Do not drive the LED from a GPIO directly; the current will exceed the pad rating.

Pick a GPIO that is free at boot. GPIO 14 is a poor choice on the ESP32-C3 (strapping); GPIO 10 works there.

Transmit timing

Transmit is bit-banged from the calling task, so the frame is only as clean as that task's timing. Three settings matter, and the examples ship the first one in their sdkconfig.defaults:

  • CONFIG_FREERTOS_HZ=1000 (default 100). Spaces longer than 16 ms yield whole ticks to the scheduler and busy-wait the rest, so the tick sets the busy-wait tail before the next mark; 1 ms is what Arduino uses. The frame timing is correct at 100 Hz too, but protocols with long gaps (Kelvinator/Gree, Daikin, Mitsubishi...) spend up to 20 ms spinning per gap.
  • CONFIG_IRREMOTE_TX_HW_CARRIER=y. Without it the 38 kHz carrier is toggled in software, and its shape depends on the optimisation level and on anything that preempts the task mid-mark.
  • Do not do other work from the sending task while a frame is on the air: no logging, no LED updates, no RMT. Anything that blocks mid-frame stretches a mark or a space. Do it before or after send().

Receiving

#include "IRrecv.h"
#include "IRutils.h"
#include "IRac.h"

static IRrecv irrecv(/*pin=*/14, /*bufsize=*/1024, /*timeout_ms=*/50,
                     /*save_buffer=*/true);
static decode_results results;

extern "C" void app_main(void) {
  irrecv.enableIRIn();
  while (true) {
    if (irrecv.decode(&results)) {
      printf("%s\n", resultToHumanReadableBasic(&results).c_str());
      String ac = IRAcUtils::resultAcToString(&results);
      if (ac.length()) printf("%s\n", ac.c_str());
    }
    vTaskDelay(pdMS_TO_TICKS(10));
  }
}

timeout_ms is how long the line must stay quiet before a message is considered finished. 15 ms suits normal remotes; A/C remotes need 50 ms or more.

Air conditioners

IRac exposes one struct that maps onto every supported climate protocol:

IRac ac(4);
ac.next.protocol = decode_type_t::COOLIX;
ac.next.power = true;
ac.next.mode = stdAc::opmode_t::kCool;
ac.next.degrees = 24;
ac.next.celsius = true;
ac.next.fanspeed = stdAc::fanspeed_t::kMedium;
ac.sendAc();

Switching brands is a one-line change. See docs/SupportedProtocols.md for the full list and which features each protocol carries.

Configuration (idf.py menuconfig)

Under Component config → IRremote (infrared send/receive):

Option Default Effect
Enable every supported protocol on Turn off to pick protocols individually and shrink the build.
Protocols → <name>: send / decode follows the above One switch per protocol direction, 241 in total.
Generate the transmit carrier in hardware (LEDC) off Offloads the 30–60 kHz carrier to an LEDC channel.
Language/locale for human readable output en-AU 15 locales available, es-ES among them.
Print library debug output off Enables the internal DPRINT tracing.

Trimming is worth real flash: the ir_receive_dump example is 318 KB with every protocol enabled and 188 KB with NEC only.

Command-line -D flags still take priority, so an existing recipe such as -D_IR_ENABLE_DEFAULT_=false -DDECODE_NEC=true keeps working:

target_compile_definitions(${COMPONENT_LIB} PUBLIC
    _IR_ENABLE_DEFAULT_=false DECODE_NEC=true SEND_NEC=true)

Examples

Example What it shows
ir_send_demo Sending NEC / Sony / Samsung / RC5 and raw timings.
ir_receive_dump Decoding, human-readable output and a pasteable raw dump.
ac_control Driving an air conditioner through IRac.
ir_repeater Capture and rebroadcast, including unknown protocols.
cd examples/ir_receive_dump
idf.py set-target esp32
idf.py build flash monitor

Tests

The complete upstream test suite runs on the host against these sources — 83 binaries, 1669 cases:

git clone -b v1.12.x --depth 1 https://github.com/google/googletest.git lib/googletest
make -C test run

CI

Workflow Runs on What it checks
ci.yml push, PR Host unit tests; the 4 examples on esp32/s3/c3 against IDF 5.1, 5.5 and 6.0; ir_receive_dump on all 9 declared targets; the LEDC carrier, debug, locale and minimal-protocol build options; that compote component pack accepts the manifest; that Kconfig matches the generator.
lint.yml push, PR cpplint over src/ and include/ with the upstream style rules, flake8 over tools/, yamllint over the manifests and workflows.
docs.yml push to main Doxygen (warnings are errors), published to GitHub Pages.
release.yml tag v* Checks the tag matches idf_component.yml and has a CHANGELOG.md section, uploads the component to the ESP Component Registry, then cuts a GitHub Release from that section. Safe to re-run: a version already published or a release already created is skipped.

release.yml needs an IDF_COMPONENT_API_TOKEN secret, generated from your account on components.espressif.com.

To release, bump version: in idf_component.yml, rename ## Unreleased in CHANGELOG.md to the same version, merge, then push a tag from main:

git tag -s v1.0.1 -m v1.0.1 && git push origin v1.0.1

Pushing the tag is the whole release; there is no need to draft it in the GitHub web UI.

Differences from IRremoteESP8266

The user-facing API is unchanged apart from a few platform-specific corners. See docs/PORTING.md for the details and how the transmit and receive paths are implemented on ESP-IDF.

License

LGPL-2.1, inherited from IRremoteESP8266. The original copyright notices are kept in every file. See LICENSE.

Upstream authors: David Conran, Mark Szabo, Sebastien Warin, Ken Shirriff, Roi Dayan, Massimiliano Pinto, Christian Nilsson and the IRremoteESP8266 contributors.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages