VE1DX
Published © GPL3+

Repurpose Old Remote Controls

Don't throw away those old TV, DVD, etc., remotes because they can control your house's electrical devices!

IntermediateFull instructions provided24,950
Repurpose Old Remote Controls

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
5 mm LED: Red
5 mm LED: Red
One red one for the status LED, after that, the colour is not really important - just need to be able to identify which one is active.
×3
5 mm LED: Green
5 mm LED: Green
Colour is not really important - just need to be able to identify which one is active
×1
5 mm LED: Yellow
5 mm LED: Yellow
Colour is not really important - just need to be able to identify which one is active
×1
Blue LED
Colour is not really important - just need to be able to identify which one is active
×2
Solderless Breadboard Full Size
Solderless Breadboard Full Size
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Toggle Switch, (Off)-On
Toggle Switch, (Off)-On
Any SPST toggle switch will work
×1
SparkFun Breadboard Power Supply Stick 5V/3.3V
SparkFun Breadboard Power Supply Stick 5V/3.3V
Optional if you can supply 5 volts from another source or if you are using it from your computer's USB connection,
×1
IR receiver (generic)
I used a KY-022 37.9KHz Infrared IR Sensor Receiver that I obtained from Amazon
×1

Story

Read more

Schematics

Breadboard layout with a Nano

Code

IR Remote repurposing sketch

Arduino
/*

  Toggle 6 LEDs using an IR remote to illustrate
  how to re-purpose surpulus remotes so they can be
  used to control almost any device.
  
  This sketch learns the manufacturer's codes for 
  the 1,2,3,4,5,6 and 0 buttons on any IR remote 
  when the toggle switch is in the "Learn" or program
  position. These values are saved in the Arduino Nano's 
  EEPROM. When the toggle switch is put in the "Run" mode,
  these values are used to determine which key is pressed.

  6 associated LEDs are then be toggled on and off by
  the remote. This is to demonstrate how to learn and 
  ise the codes regardless of the type of IR remote. In 
  addition to LEDs, the outputs can be expanded to turn 
  on or off devices with relays, high-power transistors,etc.
  
  Paul M Dunphy VE1DX

  March 2020
  
*/
 
// Include IR Remote Library developed by Ken Shirriff
#include <IRremote.h>
// Give the ability to read/write to the 1024 bytes of EEPROM
#include <EEPROM.h>

long unsigned int intIRCode;
long unsigned int savedIRCodes[6];
long unsigned int dupeCheck[6];
 
// Define pin for the IR sensor
const int Recv_Pin = 2;
 
// Define pin constants to toggle the LEDs
const int PinOne     = 12; 
const int PinTwo     = 11;
const int PinThree   = 10; 
const int PinFour    = 9;
const int PinFive    = 8; 
const int PinSix     = 7;

// Define pin constants to read and indicate the
// status of Run/Learn toggle switch.
const int switchPin  = 4;    
const int statusPin  = 5; 

const unsigned long int repeatKeyPress = 0xFFFFFFFF;

boolean learnMode; // Used to keep track of which
                   // mode we are in as per the toggle switch.
boolean first_iteration;                   

// Define integers to remember toggle states of each LED
int togglestate1;
int togglestate2;
int togglestate3;
int togglestate4;
int togglestate5;
int togglestate6;

int current_remote_code;

int  remote_code_1;
int  remote_code_2;
int  remote_code_3;
int  remote_code_4;
int  remote_code_5;
int  remote_code_6;

 
// Define IR Receiver and Results Objects
IRrecv irrecv(Recv_Pin);
decode_results results;




void EEPROMWritelong(int address, long value)

// Write a 4 byte (32bit) long integer to the EEPROM
// Since they are 4 bytes long, they are stored at 
// address to address + 3
    {
      // Decompose a long integer into 4 bytes by using bitshift.
      // One = Most significant -> Four = Least significant byte
      byte four = (value & 0xFF);
      byte three = ((value >> 8) & 0xFF);
      byte two = ((value >> 16) & 0xFF);
      byte one = ((value >> 24) & 0xFF);
      EEPROM.write(address, four);
      EEPROM.write(address + 1, three);
      EEPROM.write(address + 2, two);
      EEPROM.write(address + 3, one);
    }




long EEPROMReadlong(long address)

// Read a 4 byte (32bit) long integer from the EEPROM.
// Since they are 4 bytes long, they were stored at 
// address to address + 3
    {
      long four  = EEPROM.read(address);
      long three = EEPROM.read(address + 1);
      long two   = EEPROM.read(address + 2);
      long one   = EEPROM.read(address + 3);

      //Assemble the bytes into a long integer and return
      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + 
             ((two << 16) & 0xFFFFFF) + ((one << 24) & repeatKeyPress);
    }






int Flip_LED(int led, int toggle_state)

  {
    if(toggle_state==0)
      {
        digitalWrite(led, HIGH);
        toggle_state=1;
       }
     else 
       {
         digitalWrite(led, LOW);
         toggle_state=0;
       }
     return toggle_state;  
  }





void Reset()
  {
    // Turn all LEDs off and set the toggle
    // flags to off (0)
    digitalWrite(PinOne,   LOW);
    digitalWrite(PinTwo,   LOW);
    digitalWrite(PinThree, LOW);
    digitalWrite(PinFour,  LOW);
    digitalWrite(PinFive,  LOW);
    digitalWrite(PinSix,   LOW);
    togglestate1 = 0;
    togglestate2 = 0;
    togglestate3 = 0;
    togglestate4 = 0;
    togglestate5 = 0;
    togglestate6 = 0;
  }




void guessType()
  {
    Serial.print("Remote appears to be a ");
     switch (results.decode_type){
     case NEC: 
       Serial.println("NEC "); 
       break;
     case SONY: 
       Serial.println("SONY "); 
       break;
     case RC5: 
       Serial.println("RC5 "); 
       break;
     case RC6: 
       Serial.println("RC6 "); 
       break;
     case DISH: 
       Serial.println("DISH "); 
        break;
     case SHARP: 
       Serial.println("SHARP "); 
       break;
     case JVC: 
       Serial.println("JVC "); 
       break;
     case SANYO: 
       Serial.println("SANYO "); 
       break;
     case MITSUBISHI: 
       Serial.println("MITSUBISHI "); 
       break;
     case SAMSUNG: 
       Serial.println("SAMSUNG "); 
       break;
     case LG: 
       Serial.println("LG "); 
       break;
       case WHYNTER: 
         Serial.println("WHYNTER "); 
         break;
       case AIWA_RC_T501: 
         Serial.println("AIWA_RC_T501 "); 
         break;
       case PANASONIC: 
         Serial.println("PANASONIC "); 
         break;
       case DENON: 
         Serial.println("DENON "); 
         break;
       default:
       case UNKNOWN: 
         Serial.println("UNKNOWN "); 
         break;
      }
    }
    



int learnCodeRead(int pinCode)

  {  
     if (irrecv.decode(&results))
      {
        pinCode = results.value;
      }
    return pinCode;
  }
  
  

void Confirm()
  {
    int i;

    for(i=0; i<=20; i++)
      {
        digitalWrite(statusPin,   HIGH);
        delay(50);
        digitalWrite(statusPin,   LOW);
        delay(50);
      }  
     digitalWrite(statusPin,   HIGH); // Leave "Learn" LED high
  }


  


void learn_Mode()
  {
    boolean goodCode; 
    int i, j;
    int location;
    int pins[6] = {12,11,10,9,8,7};
 
    // Start listening for each in sequence
       if (first_iteration) 
        {
          Serial.println();
          Serial.println("Entering learn mode");
          Serial.println();
        }
    intIRCode = 0;
    location = 0;
    goodCode = true;
    j = 0;
    while ((goodCode=true) and (j<=5))
      {
        for(i=0; i<=25; i++)
        {
          digitalWrite(pins[j],   HIGH);
          delay(200);
          intIRCode = learnCodeRead(intIRCode);
          digitalWrite(pins[j],   LOW);
          delay(200);
          intIRCode = learnCodeRead(intIRCode);
          goodCode = ((intIRCode !=repeatKeyPress) and (intIRCode !=0));
          if (goodCode) 
            { 
              i=30; // Trick to bail out of loop because 'break' 
                    // doesn't work on loops
            }
          irrecv.resume();     // Start listening again  
        }
        goodCode = (intIRCode !=repeatKeyPress and intIRCode !=0);
        if (goodCode)
          {   
            if (j==0) 
              {
                guessType();
              }
            Serial.print("Writing to EEPROM Location ");Serial.print(location); 
            Serial.print("  IR code = ");Serial.println(intIRCode,HEX);
            EEPROMWritelong(location, intIRCode);        
            location = location + 4;
            j++;
            Confirm();
            intIRCode = 0;
            irrecv.resume();     // Start listening again
           }
          
      }
        Serial.println();
        Serial.println("Put Arduino back in run mode.");
        while (digitalRead(switchPin) == HIGH)
          {
            digitalWrite(statusPin,   HIGH);
            delay(1000);
            digitalWrite(statusPin,   LOW);
            delay(1000);
          } 
        Serial.println();
        Serial.println("Returning to run mode.");
        
        // Probably don't need to be so drastic here, but
        // This is a "reset" to be sure we get out of learn
        // mode and restart properly. It's *likely* OK to
        // remove the following 4 lines.
        delay(50);
        Serial.flush(); 
        delay(50);
        asm volatile ("  jmp 0");
  }




  

void run_Mode()
  {
    if (first_iteration) 
      {
        Serial.println("Entering run mode");
      }
    if (irrecv.decode(&results))
      {
        if (results.value!=repeatKeyPress) {
        current_remote_code = results.value; 
        Serial.print("Key press detected, IR code = "); 
        Serial.println(current_remote_code,HEX);
        if (current_remote_code == remote_code_1)
          {
            togglestate1 = Flip_LED(PinOne,togglestate1);
           }
        else if (current_remote_code == remote_code_2) {
            togglestate2 = Flip_LED(PinTwo,togglestate2);
                             }
        else if (current_remote_code == remote_code_3) {
            togglestate3 = Flip_LED(PinThree,togglestate3);
                             }
        else if (current_remote_code == remote_code_4) {
           togglestate4 = Flip_LED(PinFour,togglestate4);
                             }
        else if (current_remote_code == remote_code_5) {
           togglestate5 = Flip_LED(PinFive,togglestate5);
                             }   
        else if (current_remote_code == remote_code_6) {
           togglestate6 = Flip_LED(PinSix,togglestate6);
                             }
        else  {
            Reset();
              } 
      }                                            
         delay(500);         // Used to get around the rapid string of data
                             // if a button is held down. Slows down response time
                             // by introducing a lag in the loop.                             
        irrecv.resume();     // Start listening again  
      }
  } 


 

 
void setup()
  {
    first_iteration = true;
    int i,j,k;
    int location; 
    int dupeFlash[6] = {12,11,10,9,8,7}; // Pin numbers to flash
                                         // if duplicates found
    
    Serial.begin(9600);
    irrecv.enableIRIn(); // Enable the IR Receiver

 /* The following section of code should never need to be reset the EEPROM.
  * However, some new, off "the shelf" NANOs show up with their EEPROMs set 
  * to FFFFFFFFs. This happens to be the code sent by many IR Remotes when 
  * a key is held down. This sketch checks for that code in several places
  * and it won't work properly if a "key" is assigned a hex FFFFFFFF. To 
  * prevent this gotcha, we check for FFFFFFFFs and if we find one, we set 
  * the 6 key locations to Sony RM-YD104 codes.  If this happens, unless you
  * are using that particular remote, you'll need to run the sketch in "learn"
  * mode to initialise it.
  */

// ============= Begin New Arduino ==================

   boolean defaultToSony = false;
   long unsigned int IRCode = 0;
   location = 0;
   for(i=0; i<=5; i++)
      {     
        IRCode = EEPROMReadlong(location);
        if (IRCode==repeatKeyPress)
          {
            defaultToSony = true;
          }          
        location = location + 4;
      } 
    if (defaultToSony) 
      {
        Serial.println("HEX FFFFFFFF found in EEPROM memory. Setting codes");
        Serial.println("for a Sony RM-YD104 remote. Running 'learn' mode now");
        Serial.println("is recommended unless that's the remote you have.");
        EEPROMWritelong(0, 0x10);
        delay(50);
        EEPROMWritelong(4, 0x810);
        delay(50);
        EEPROMWritelong(8, 0x410);
        delay(50);
        EEPROMWritelong(12, 0xC10);
        delay(50);  
        EEPROMWritelong(16, 0x210);
        delay(50); 
        EEPROMWritelong(20, 0xA10);
        delay(50);                             
      } 


// ============= End New Arduino ==================
  
    // Set LED pins as outputs
    pinMode(PinOne,   OUTPUT);
    pinMode(PinTwo,   OUTPUT);
    pinMode(PinThree, OUTPUT);
    pinMode(PinFour,  OUTPUT);
    pinMode(PinFive,  OUTPUT);
    pinMode(PinSix,   OUTPUT);
  
    Reset(); // Start out with them all off
  
    pinMode(statusPin, OUTPUT); 
    pinMode(switchPin, INPUT);

    //Get codes from last used remote
    Serial.println();
    Serial.println("Reading stored IR remote codes . . . ");    
    location = 0;
    for(j=0; j<=5; j++)
      {   
        savedIRCodes[j] = EEPROMReadlong(location);
        Serial.print("Reading from EEPROM Location ");Serial.print(location); 
        Serial.print("  IR code = ");Serial.println(savedIRCodes[j],HEX);
        location = location + 4;
        dupeCheck[j]=savedIRCodes[j]; // Save a copy for duplicate checking
      } 

    // Look for consecutive duplicate codes assigned to the 
    // outputs. We don't look for overall duplicates because
    // they are unlikely to happen. Experience has shown that 
    // during programming, the most likely mistake is to press
    // the same key twice on bacl-to-back LEDs.  If duplicates
    // are found, indicate this by flashing the suspect LEDs.
    // There are only 6 LEDs, so it only takes 21 comparisons
    // to find any duplicates (6 + 5 + 4 + 3 + 2 + 1 = 21). This 
    // section could be enhanced to look for any duplicates by
    // sorting the array first, etc.
    for (i = 0; i <5 - 1; i++) 
      {
        for (j = i + 1; j <6; j++)
          {
            if (dupeCheck[i] == dupeCheck[j]) 
              {
              Serial.println("Duplicate codes found. Suggest re-running learn mode");
              for(k=0; k<=5; k++)
                {
                  digitalWrite(dupeFlash[i],HIGH);
                  digitalWrite(dupeFlash[j],HIGH);
                  delay(1000);
                  digitalWrite(dupeFlash[i],LOW);
                  digitalWrite(dupeFlash[j],LOW);
                  delay(1000);
                } 
              }
          }
       }
      
      remote_code_1 = savedIRCodes[0];
      remote_code_2 = savedIRCodes[1];
      remote_code_3 = savedIRCodes[2];
      remote_code_4 = savedIRCodes[3];
      remote_code_5 = savedIRCodes[4];
      remote_code_6 = savedIRCodes[5];
      delay(1000);
      Serial.println("Stored codes read.");
      Serial.println();
    }

    
 

 
void loop()
  {  
    // Check if the toggle is on or off. If it is on (in learn mode)
    // the switchPin is HIGH:
    learnMode = (digitalRead(switchPin) == HIGH);
    if (learnMode) 
      {    
        first_iteration = true;
        Reset();
        digitalWrite(statusPin, HIGH); // Turn learn mode LED on:
        learn_Mode();
        Reset();
        first_iteration = false; 
      } 
    else 
      {  
        digitalWrite(statusPin, LOW);  // Turn learn mode LED off:
        run_Mode();  
        first_iteration = false;     
      }
     
  }

Credits

VE1DX

VE1DX

2 projects • 6 followers

Comments