How to sniff IR codes with an ESP32 microcontroller without writing a single line of code

I’ve been developing software for the ESP32 and ESP32S3 “professionally” for about one year now. I still like the Raspberry Pi Pico better, but the ESP32 line of microcontrollers is cool too. And if you need wireless and don’t really care too much about power consumption, the ESP32 (or -S3 or what have you) is a nice thing to have around.

The examples in IDF (the name of the ESP32 SDK) are really great, and you can do a bunch of stuff just by taking an example and changing a couple lines.

I’m a huge fan of the Raspberry Pi Pico’s PIO, and the ESP32 has something that is slightly similar, as-in “programmable IO”. It’s called “RMT”, and in examples/peripherals/rmt, we have a few examples that make use of this bit of silicon. The examples/peripherals/rmt/ir_nec_transceiver example is the one we look at in this article.

Basically, all you have to do is flash this to your dev board and connect an IR receiver module’s output pin to GPIO19 (and its VCC and GND to VCC and GND. Be sure to hook it up to 3.3V, not 5V.) If you want to do what this example is supposed to do (output the same signal back through an infrared LED on GPIO18), feel free. But if you just want to sniff codes, leave the infrared LED disconnected and look at the UART output.

Note that the output of the IR receiver is expected to be inverted compared to the actually sent signal. I think most IR receivers invert the signal, so you’ll most likely be fine.

Build steps

If your dev board isn’t a standard ESP32, but e.g. an ESP32S3, you first have to do:

idf.py set-target esp32s3

Then you do:

idf.py flash monitor

This will build the example, flash it to the dev board, and start a monitor.

Then you’ll see a bunch of output like this:

NEC frame start---
{0:218},{1:0}
---NEC frame end: Unknown NEC frame

But if you press a key on a remote control, you may see something like this:

NEC frame start---
{0:9120},{1:4426}
{0:632},{1:498}
{0:622},{1:512}
{0:628},{1:499}
{0:631},{1:525}
{0:606},{1:498}
{0:632},{1:525}
{0:605},{1:501}
{0:628},{1:529}
{0:602},{1:1633}
{0:615},{1:1657}
{0:610},{1:1646}
{0:610},{1:1646}
{0:610},{1:1646}
{0:611},{1:1649}
{0:605},{1:1650}
{0:606},{1:1649}
{0:607},{1:1652}
{0:603},{1:529}
{0:599},{1:530}
{0:596},{1:503}
{0:635},{1:1646}
{0:609},{1:1647}
{0:609},{1:522}
{0:608},{1:497}
{0:633},{1:522}
{0:609},{1:1647}
{0:608},{1:1648}
{0:607},{1:1650}
{0:606},{1:501}
{0:627},{1:529}
{0:600},{1:1616}
{0:642},{1:1647}
{0:610},{1:0}
---NEC frame end: Address=FF00, Command=CE31

And there you have the address and the command! Note that by default, extended NEC codes are allowed. (However, the remote control I used here generates a non-extended NEC code, where the second byte in the address (and command) is the first byte but inverted. I.e., 0xFF == ^0x00, 0xCE == ^0x31.)

And that’s all! If you output this using an IR LED (make sure you use a resistor), you will be able to control the device in question using your microcontroller. Note that you will probably have to move the LED rather close to the device you’re trying to control (depending on your resistor value). Note that you shouldn’t really exceed 30 mA per GPIO. I understand that most IR LEDs are good up to 100 mA, but the ESP32’s GPIO pins aren’t. You’ll need to amplify the signal if you want to go higher than 30 mA.

Sniffing IR (NEC) codes on the Raspberry Pi Pico

The Pico has a very similar demo, pico-examples/pio/ir_nec/ir_loopback/ir_loopback.c. If all you want to do is sniffing, it may work a little nicer if you comment out the sending stuff (everything from “// create a 32-bit frame and add it to the transmit FIFO” to “sleep_ms(100);”), as well as the sleep_ms(900) at the bottom. (Otherwise you’ll have to wait a little bit until your IR code shows up.) Also, it won’t do extended NEC codes. You’d have to modify nec_receive.c a little bit.

Leave a Reply

Your email address will not be published. Required fields are marked *