A Smarter Remote

A universal infrared remote controlled through Alexa.

7 minute read

I replaced all of the remotes in my house with a microcontroller and an infrared LED.

Controlling it through Alexa is helpful when you can’t find the standard remote or it’s too far away!

The Inspiration

My receiver doesn’t have a remote so I’ve used a classic Comcast universal remote to send it power and volume signals but buttons for changing input don’t work.

But this got me thinking: if Comcast can store a bunch of common IR signals on a remote so I bet I could hard code the ones that belong to my devices on a microcontroller.

On top of all of that, I’ll be able to control it with my voice and send batch commands (like “turn all the power off” or “go to specific input sources on each device”).

Recording All of My Remote Codes

Receiving code:

#include <IRremote.h>

#define RECV_PIN D0

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup() {
    Serial.begin(9600);
    irrecv.enableIRIn();
}

void loop() {
    if (irrecv.decode(&results)) {
        int count = results.rawlen;
        
        Serial.print("HEX: ");
        Serial.println(results.value, HEX);
        
        Serial.print("BITS: ");
        Serial.println(count, DEC);
        
        for (int i = 1; i < count; i++) {
            if (i & 1) {
                Serial.print(results.rawbuf[i]*USECPERTICK, DEC);
            } else {
                Serial.print((unsigned long) results.rawbuf[i]*USECPERTICK, DEC);
            }
            Serial.print(" ");
        }
        
        Serial.println("");
        irrecv.resume();
    }
}

The code essentially says,

  1. constantly check to see if you’re getting a message
  2. if you see something print it out encoded as hex then as a raw value

Here’s an action shot:

Thanks for the hand, lego man.

So I pressed every button I wanted to be able to mimick and I recorded the codes as they printed out to my terminal.

# screen /dev/tty.usbmodem14101 9600
HEX: 438E0879
BITS: 68
8750 4500 450 650 450 1750 500 1750 450 650 450 650 450 650 450 650 450 1750 450 1800 450 600 500 1750 450 650 450 650 450 650 450 650 450 650 450 1800 450 1750 450 1750 450 1750 450 650 450 650 500 600 500 600 500 650 450 600 500 600 500 600 500 1750 450 1750 450 1750 500 1750 450

I still have to look up what the numbers exactly mean and how it’s communicated by an LED. But if I receive ‘em, I can transmit ‘em!

Transmitting all of my remote codes

#include <IRTransmitter/IRTransmitter.h>

#define IR_PIN D6
#define LED_PIN D7

IRTransmitter transmitter(IR_PIN, LED_PIN);

//TV POWER: 61A0F00F
unsigned int tv_power[67] = {8850, 4400, 500, 600, 550, 1700, 500, 1650, 550, 600, 500, 550, 550, 550, 600, 550, 550, 1650, 500, 1700, 550, 550, 550, 1650, 600, 550, 550, 550, 550, 500, 600, 550, 550, 550, 550, 1650, 550, 1700, 500, 1700, 550, 1650, 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, 600, 550, 500, 550, 550, 500, 600, 1700, 550, 1650, 550, 1650, 550, 1650, 550};
//TV HDMI INPUT: 61A00AF5
unsigned int tv_hdmi[67] = {8800, 4450, 500, 600, 500, 1700, 500, 1700, 500, 600, 500, 600, 550, 550, 550, 550, 550, 1700, 500, 1700, 550, 600, 500, 1650, 550, 550, 550, 600, 500, 550, 550, 600, 500, 600, 500, 600, 500, 600, 550, 550, 500, 600, 550, 1650, 500, 550, 600, 1650, 550, 600, 500, 1700, 500, 1700, 550, 1650, 550, 1700, 500, 600, 500, 1700, 500, 600, 550, 1650, 550};
//TV VIDEO INPUT: 6B3B7B5F
unsigned int tv_video[67] = {8800, 4450, 500, 600, 500, 1700, 500, 1700, 500, 600, 500, 600, 550, 550, 550, 550, 550, 1700, 500, 1700, 550, 600, 500, 1650, 550, 550, 550, 600, 500, 550, 550, 600, 500, 600, 500, 600, 500, 600, 550, 550, 500, 600, 550, 1650, 500, 550, 600, 1650, 550, 600, 500, 1700, 500, 1700, 550, 1650, 550, 1700, 500, 600, 500, 1700, 500, 600, 550, 1650, 550};
//TV VOL UP: 14036CA3
unsigned int tv_vol_up[67] = {8750, 4500, 500, 600, 500, 1650, 550, 1700, 550, 550, 550, 550, 550, 550, 550, 550, 550, 1650, 550, 1700, 550, 550, 550, 1650, 500, 600, 550, 550, 500, 600, 500, 650, 450, 650, 450, 650, 450, 650, 450, 1700, 550, 1700, 500, 600, 500, 600, 500, 600, 500, 600, 500, 1750, 450, 1700, 550, 600, 500, 600, 500, 1700, 500, 1750, 450, 1700, 550, 1700, 550};
//TV VOL DOWN: 20B81A95
unsigned int tv_vol_down[67] = {8850, 4450, 450, 600, 500, 1700, 500, 1750, 500, 600, 500, 600, 500, 600, 500, 600, 500, 1700, 500, 1700, 550, 600, 500, 1700, 500, 600, 500, 600, 500, 600, 500, 600, 500, 650, 450, 1750, 450, 600, 500, 1700, 550, 1700, 500, 600, 500, 600, 500, 600, 500, 650, 450, 600, 500, 1700, 550, 550, 550, 600, 500, 1700, 500, 1700, 550, 1650, 500, 1750, 550};
//TV MUTE: C1B0B63F
unsigned int tv_mute[67] = {8800, 4450, 500, 600, 500, 1700, 550, 1700, 500, 600, 500, 600, 500, 600, 500, 600, 500, 1750, 450, 1700, 550, 600, 500, 1700, 500, 600, 500, 600, 500, 600, 500, 650, 450, 650, 450, 650, 450, 1750, 450, 1750, 500, 1700, 500, 600, 500, 650, 500, 600, 450, 650, 500, 1700, 550, 550, 550, 550, 550, 550, 550, 1650, 550, 1700, 500, 1700, 450, 1750, 550};
//AUX POWER: 1DE2B946
unsigned int aux_power[67] = {8750, 4400, 550, 550, 550, 550, 500, 600, 500, 1700, 500, 1700, 500, 1650, 550, 500, 600, 1650, 500, 1700, 500, 1700, 500, 1650, 550, 500, 600, 550, 550, 550, 550, 1650, 550, 550, 500, 1700, 500, 600, 500, 1700, 450, 1700, 500, 1700, 550, 550, 500, 600, 500, 1650, 550, 600, 500, 1650, 550, 550, 550, 550, 550, 550, 550, 1650, 500, 1700, 500, 600, 500};
//AUX MUTE: EF3B3AE4
unsigned int aux_mute[67] = {8700, 4450, 450, 600, 500, 650, 450, 600, 500, 1700, 500, 1700, 450, 1750, 450, 650, 500, 1650, 500, 1700, 500, 1700, 500, 1700, 450, 600, 500, 650, 450, 650, 450, 1700, 500, 600, 500, 600, 500, 650, 450, 1700, 450, 1750, 450, 1750, 450, 600, 500, 650, 450, 1750, 450, 1700, 450, 1750, 500, 600, 450, 650, 450, 650, 450, 1750, 450, 1700, 500, 600, 450};
//AUX VOL UP: 1DE2D926
unsigned int aux_vol_up[67] = {8750, 4400, 500, 600, 500, 600, 500, 600, 500, 1700, 500, 1700, 500, 1650, 500, 600, 500, 1700, 500, 1700, 500, 1700, 500, 1700, 500, 600, 450, 600, 500, 600, 500, 1700, 500, 600, 500, 1700, 500, 1700, 500, 600, 500, 1650, 500, 1700, 500, 600, 500, 600, 500, 1700, 500, 600, 500, 550, 550, 1650, 500, 600, 500, 600, 500, 1700, 500, 1700, 500, 600, 500};
//AUX VOL DOWN: 915A4CBC
unsigned int aux_vol_down[67] = {8750, 4400, 550, 600, 500, 600, 500, 550, 500, 1700, 450, 1750, 500, 1700, 500, 550, 550, 1650, 550, 1650, 500, 1700, 500, 1700, 500, 550, 550, 550, 500, 600, 550, 1650, 500, 600, 450, 650, 450, 1750, 500, 600, 450, 1700, 550, 1650, 550, 600, 450, 600, 500, 1700, 450, 1750, 500, 600, 500, 1650, 500, 600, 500, 650, 450, 1700, 500, 1700, 550, 550, 500};
                        

void setup() {
    Particle.function("transmit", transmit);
}

void loop() {
}

int transmit(String args) {
    if (args == "tv_power") {
        transmitter.Transmit(tv_power, sizeof(tv_power) / sizeof(tv_power[0]));
        return 1;
    } else if (args == "tv_hdmi") {
        transmitter.Transmit(tv_hdmi, sizeof(tv_hdmi) / sizeof(tv_hdmi[0]));
        return 1;
    } else if (args == "tv_video") {
        transmitter.Transmit(tv_video, sizeof(tv_video) / sizeof(tv_video[0]));
        return 1;
    } else if (args == "tv_vol_up") {
        transmitter.Transmit(tv_vol_up, sizeof(tv_vol_up) / sizeof(tv_vol_up[0]));
        return 1;
    } else if (args == "tv_vol_down") {
        transmitter.Transmit(tv_vol_down, sizeof(tv_vol_down) / sizeof(tv_vol_down[0]));
        return 1;
    } else if (args == "tv_mute") {
        transmitter.Transmit(tv_mute, sizeof(tv_mute) / sizeof(tv_mute[0]));
        return 1;
    } else if (args == "aux_power") {
        transmitter.Transmit(aux_power, sizeof(aux_power) / sizeof(aux_power[0]));
        return 1;
    } else if (args == "aux_mute") {
        transmitter.Transmit(aux_mute, sizeof(aux_mute) / sizeof(aux_mute[0]));
        return 1;
    } else if (args == "aux_vol_up") {
        transmitter.Transmit(aux_vol_up, sizeof(aux_vol_up) / sizeof(aux_vol_up[0]));
        delay(200);
        transmitter.Transmit(aux_vol_up, sizeof(aux_vol_up) / sizeof(aux_vol_up[0]));
        return 1;
    } else if (args == "aux_vol_down") {
        transmitter.Transmit(aux_vol_down, sizeof(aux_vol_down) / sizeof(aux_vol_down[0]));
        delay(200);
        transmitter.Transmit(aux_vol_down, sizeof(aux_vol_down) / sizeof(aux_vol_down[0]));
        return 1;
    } else if (args == "all_power") {
        transmitter.Transmit(tv_power, sizeof(tv_power) / sizeof(tv_power[0]));
        delay(200);
        transmitter.Transmit(aux_power, sizeof(aux_power) / sizeof(aux_power[0]));
        return 1;
    } else {
        return -1;
    }
}

IFTTT connection

You can call the code on your Particle as a IFTTT Actions.

So here we’re going to create an Alexa Phrase Trigger on IFTTT which will then pass a command to the transmit function.

IFTTT Alexa Trigger IFTTT Particle Action

After that I wanted to put the device out of sight but make it visible to every device it’s programmed to control.

There’s only one thing left. Let’s give it a try!