Project in progress
IoT IR Programmable Transcoder - TV Remote on Steroids

IoT IR Programmable Transcoder - TV Remote on Steroids © GPL3+

One code goes in, another comes out... A different way of having a single remote without needing a universal one.

  • 2,647 views
  • 3 comments
  • 9 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

Background

You when something annoys you so much you just have to fix it especially if every one else nags you. Our television remote falls in this category, its a "Dick Smith" brand unit and has a dodgy intermittent remote. I've used universal remotes before and even after hours of programming them they are not so flash. So what to do? Our Panasonic DVR we use has a more than adequate universal section built in but in spite of talking to 100s of other devices our TV is not one of them. If only it spoke the lingo!

Arduino IR library and Nano on the job

Did you know with a couple of parts you can receive, analyse and send IR codes with even the smallest Arduino? So with not much more than the example sketch you can work out what codes in what protocol gets sent from your remote for each button. With a couple more lines of code you can send another code that you would like substituted for the the first code.

So in no time at all you have built yourself a transcoder. Receives codes of one remote and re-transmits them as if from another. "Piece of Pi" or maybe Arduino? I even put in the start of an overlay function so I can use all of the remote buttons for the TV if the original device is off, I used a RGB LED indicator to show when your in that mode to avoid user confusion.

Anyhow, all that is left now is to give the remote to family members to test and suggest while you watch for bugs.

The circuit

Very simple, due to the IR receiver doing a lot of the heavy lifting. It has the automatic gain control and many other items needed to successfully demodulate the 38 kHz signal that is passed to the Arduino. There is no current limmit resistor on the two IR LEDs. I was expecting scorch marks on the couch while testing but it seems to work fine at 5V with the LEDs I bought. Trying this was a response to what seemed a pathetic range at 20 ma, "More power Igor !"

You can see the proof of concept test unit with the breadboard to the left of our TV. The Arduino Nano is mounted on a prototype shield to the right. These prototype shields are neat as no toolkit should be without one!

Not all beer and Skittles

There are some subtle things at play in the project and its all in the timing of the reception and transmission of the new code. but as always "Professor Google" has most of the answers that you seek.

Worthwhile?

Definitely, I only need one remote which I didn't have to buy. I can change functionality (Include some macros) if I wish. Most importantly I learned a lot about IR remote controls.

But wait there's more... ESP to the rescue!

All the parts for the final build sat on my bench for 12 months, assigned to the back burner after some success with a soldering iron and the actual TV remote. In the mean time I learned about the ESP8266. So when it can to put the unit in a box I thought why not make it run on a NodeMCU board. So with that thought in mind the final chapter and build was started.

So the software was rearranged and refactored to suit the new and better IR library for the ESP8266. The tri-color LED was used as follows. Red flash for IR transmit, Blue flash for WiFi Receive and Green flash for IR receive. The Blue LED also flashes fast during the boot phase as it attempts to login to the WiFi. The built in LED is used as a confidence meter / heart beat.

The unit has both soft AP and WiFi client, This makes configuration easier as there is always a configuration port available.

The remote control page uses some in-line CSS in the web response to set the style of the form buttons which form the basis of the remote control page. The page works nicely on mobile phones due to the "viewport" command which helps the phone get a better "perspective" on how it should display the content. These represent a departure from my usual web M.O but I am trying to "up skill" a bit.

But wait... how could I build a remote control that has WiFi with making it programmable via the WiFi and IR port. So a new web page and interface was designed so I could capture an IR code and assign it to a button in the control matrix. In fact you can reprogram it all via this interface. There is a factory reset to return it to the original state if you completely loose your way.

Actually I found the virtual remote on a mobile web page much handier than just a gimmick. Every member of the family has some sort of device and can now operate the TV even if the remote has scurried away into the deepest recesses of the sofa.

Hmmm.... works well but could be better. I found myself wanting more devices on the virtual remote. There be enough EEPROM memory so lets Implement 3 pages of 48 buttons (4 x 12). This doesn't really impact the rest of the code and really just increases the lookup table for the transcode function. So that will no doubt be the next improvement..

Strangely enough the wee transcoder box helped shine some light on our troublesome TV remote. I was under the impression it wasn't transmitting at all. However I noticed the green light flashing (code received) but the TV not responding. So what curiosity led me to the setup page where I discovered the remote was sending the wrong codes! No wonder the TV doesn't respond, but armed with knowledge a fix may me close at hand.

As usual, thanks to all those that helped and happy coding!

Update June 2019

Yes I've sort of finished the code for the multipad version shown above, it's listed in GitHub and it's running in our living room. Constructive comments welcome.

Code

Trans-coder for Arduino NanoC/C++
Version 0.75 First very rough cut - Proof of concept
Done back in 2016 so coding is very rough but does work and solve the problem
//------------------------------------------------------------------------------
// Include the IRremote library header
//
#include <IRremote.h>

#define DECODE_NEC 1
#define TVONOFF   0xFB38C7
#define TVAV      0xFBE817   // signal source
#define TVVOLUP   0xFBD22D
#define TVVOLDN   0xFBF20D
#define TVCHUP    0xFB906F
#define TVCHDN    0xFBA05F
#define TV1PAD    0xFB2AD5
#define TV2PAD    0xFB6897    
#define TV3PAD    0xFBA857
#define TV4PAD    0xFB0AF5
#define TV5PAD    0xFB48B7
#define TV6PAD    0xFB8877
#define TV7PAD    0xFB32CD
#define TV8PAD    0xFB708F
#define TV9PAD    0xFBB04F
#define TV0PAD    0xFB30CF
#define TVLNAV    0xFBE21D
#define TVRNAV    0xFBE01F
#define TVUNAV    0xFB58A7
#define TVDNAV    0xFB12ED
#define TVOKNAV   0xFB609F
#define TVAPMENU  0xFB18E7
#define TVEXITNAV 0xFB50AF
#define TVMUTE    0xFB10EF
#define TVPLAY    0xFB5AA5
#define TVPAUSE   0xFB4AB5
#define TVSTOP    0xFBBA45
#define TVWTF     0xFB3AC5
#define TVREW     0xFBAA55
#define TVFF      0xFB7A85
#define TVPREV    0xFB8A75
#define TVNEXT    0xFB9A65
#define TVTEXT    0xFB9A65
#define TVSUBTTL  0xFBFA05
#define TVFREEZE  0xFB9867
#define TVINFO    0xFB1AE5
#define TVRED     0xFB6A95
#define TVGREEN   0xFBEA15
#define TVYELLOW  0xFBF807
#define TVBLUE    0xFBDA25

  
IRsend irsend;
long PrevCode;
int iMode = 0;
bool bTransmit=false;
bool bRepeat=false;
//------------------------------------------------------------------------------
// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838)
//
int recvPin = 11;
IRrecv irrecv(recvPin);


//+=============================================================================
// Configure the Arduino
//
void  setup ( )
{
  Serial.begin(115200);   // Status message will be sent to PC at 9600 baud
  Serial.println("Start");
  pinMode(3,OUTPUT);  // IR LED
  pinMode(4,OUTPUT);  // RGB LED FOR MODE INDICATOR
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  irrecv.enableIRIn();  // Start the receiver
  irrecv.blink13(1);
}

//+=============================================================================
// Display IR code
//
void  ircode (decode_results *results)
{
  // Panasonic has an Address
  if (results->decode_type == PANASONIC) {
    Serial.print(results->address, HEX);
    Serial.print(":");
  }

  // Print Code
  Serial.print(results->value, HEX);
}

//+=============================================================================
// Display encoding type
//
void  encoding (decode_results *results)
{
  switch (results->decode_type) {
    default:
    case UNKNOWN:      Serial.print("UNKNOWN");       break ;
    case NEC:          Serial.print("NEC");           break ;
    case SONY:         Serial.print("SONY");          break ;
    case RC5:          Serial.print("RC5");           break ;
    case RC6:          Serial.print("RC6");           break ;
    case DISH:         Serial.print("DISH");          break ;
    case SHARP:        Serial.print("SHARP");         break ;
    case JVC:          Serial.print("JVC");           break ;
    case SANYO:        Serial.print("SANYO");         break ;
    case MITSUBISHI:   Serial.print("MITSUBISHI");    break ;
    case SAMSUNG:      Serial.print("SAMSUNG");       break ;
    case LG:           Serial.print("LG");            break ;
    case WHYNTER:      Serial.print("WHYNTER");       break ;
    case AIWA_RC_T501: Serial.print("AIWA_RC_T501");  break ;
    case PANASONIC:    Serial.print("PANASONIC");     break ;
    case DENON:        Serial.print("Denon");         break ;
  }
}

//+=============================================================================
// Dump out the decode_results structure.
//
void  dumpInfo (decode_results *results)
{
  // Check if the buffer overflowed
  if (results->overflow) {
    Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWLEN");
    return;
  }

  // Show Encoding standard
  Serial.print("Encoding  : ");
  encoding(results);
  Serial.println("");

  // Show Code & length
  Serial.print("Code      : ");
  ircode(results);
  Serial.print(" (");
  Serial.print(results->bits, DEC);
  Serial.println(" bits)");
}

//+=============================================================================
// Dump out the decode_results structure.
//
void  dumpRaw (decode_results *results)
{
  // Print Raw data
  Serial.print("Timing[");
  Serial.print(results->rawlen-1, DEC);
  Serial.println("]: ");

  for (int i = 1;  i < results->rawlen;  i++) {
    unsigned long  x = results->rawbuf[i] * USECPERTICK;
    if (!(i & 1)) {  // even
      Serial.print("-");
      if (x < 1000)  Serial.print(" ") ;
      if (x < 100)   Serial.print(" ") ;
      Serial.print(x, DEC);
    } else {  // odd
      Serial.print("     ");
      Serial.print("+");
      if (x < 1000)  Serial.print(" ") ;
      if (x < 100)   Serial.print(" ") ;
      Serial.print(x, DEC);
      if (i < results->rawlen-1) Serial.print(", "); //',' not needed for last one
    }
    if (!(i % 8))  Serial.println("");
  }
  Serial.println("");                    // Newline
}

//+=============================================================================
// Dump out the decode_results structure.
//
void  dumpCode (decode_results *results)
{
  // Start declaration
  Serial.print("unsigned int  ");          // variable type
  Serial.print("rawData[");                // array name
  Serial.print(results->rawlen - 1, DEC);  // array size
  Serial.print("] = {");                   // Start declaration

  // Dump data
  for (int i = 1;  i < results->rawlen;  i++) {
    Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
    if ( i < results->rawlen-1 ) Serial.print(","); // ',' not needed on last one
    if (!(i & 1))  Serial.print(" ");
  }

  // End declaration
  Serial.print("};");  // 

  // Comment
  Serial.print("  // ");
  encoding(results);
  Serial.print(" ");
  ircode(results);

  // Newline
  Serial.println("");

  // Now dump "known" codes
  if (results->decode_type != UNKNOWN) {

    // Some protocols have an address
    if (results->decode_type == PANASONIC) {
      Serial.print("unsigned int  addr = 0x");
      Serial.print(results->address, HEX);
      Serial.println(";");
    }

    // All protocols have data
    Serial.print("unsigned int  data = 0x");
    Serial.print(results->value, HEX);
    Serial.println(";");
  }
}

//+=============================================================================
// The repeating section of the code
//
void  loop ( )
{
  decode_results  results;        // Somewhere to store the results

  if (irrecv.decode(&results)) {  // Grab an IR code
    dumpInfo(&results);           // Output the results
    dumpRaw(&results);            // Output the results in RAW format
    dumpCode(&results);           // Output the results as source code
    Serial.println("");           // Blank line between entries

    
//    Serial.println(iMode);
    Serial.print("R ");
    Serial.println(results.value, HEX);

    bTransmit = false ;
    switch(results.value){
      case 0x18E710EF:   // TV on off
          PrevCode = TVONOFF ;
          bTransmit = true ;
          bRepeat = false ;
          iMode = 0 ;
      break;
      case 0x18E750AF:    // AV
          PrevCode = TVAV ;
          bTransmit = true ;
          bRepeat = false ;
          iMode = 0 ;
      break;
      case 0x18E740BF:   // VOL +
          PrevCode = TVVOLUP ;
          bTransmit = true ;
          bRepeat = true ;
          iMode = 0 ;
      break;
      case 0x18E7C03F:  // VOL -
          PrevCode = TVVOLDN ;
          bTransmit = true ;
          bRepeat = true ;
          iMode = 0 ;
      break;
      case 0x18E700FF:   // CH +
          PrevCode = TVCHUP ;
          bTransmit = true ;
          bRepeat = false ;
          iMode = 0 ;
      break;
      case 0x18E7807F:    // CH-
          PrevCode = TVCHDN ;
          bTransmit = true ;
          bRepeat = false ;
          iMode = 0 ;
      break;
      case 0xFFFFFFFF:    // repeat code
          if ( bRepeat == true ){
            bTransmit = true ;
          }
      break;

      case 0xD880287:  // blue button
        if ( iMode != 1 ){
          iMode = 1;
        }else{
          iMode = 0;
        }
        bRepeat = false ;
      break;
      case 0xD88C247:  // yellow button
          PrevCode = TVMUTE ;
          bTransmit = true ;
          bRepeat = false ;
          iMode = 0 ;
      break;
      case 0xD8842C7:  // green button
        if ( iMode != 3 ){
          iMode = 2;
        }else{
          iMode = 0;
        }
        bRepeat = false ;        
      break;
      case 0xD888207:  // red button
        if ( iMode != 4 ){
          iMode = 3;
        }else{
          iMode = 0;
        }
        bRepeat = false ;        
      break;
      case 0xD08E1E4:  // left nav
        if ( iMode == 1 ){
          PrevCode = TVLNAV ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD081114:  // right nav
        if ( iMode == 1 ){
          PrevCode = TVRNAV ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD086164:  // down nav
        if ( iMode == 1 ){
          PrevCode = TVDNAV ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08A1A4:  // up nav
        if ( iMode == 1 ){
          PrevCode = TVUNAV ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD084144:  // ok nav
        if ( iMode == 1 ){
          PrevCode = TVOKNAV ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD888A0F:  // exit nav
        if ( iMode == 1 ){
          PrevCode = TVEXITNAV ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD086663:  // status nav
          bRepeat = false ;
      break;
      case 0xD088184:  // return nav
          bRepeat = false ;
      break;
      case 0xD08080D:  // 1 nav pad
        if ( iMode == 1 ){
          PrevCode = TV1PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08888D:  // 2 nav pad
        if ( iMode == 1 ){
          PrevCode = TV2PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08484D:  // 3 nav pad
        if ( iMode == 1 ){
          PrevCode = TV3PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08C8CD:  // 4 nav pad
        if ( iMode == 1 ){
          PrevCode = TV4PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08282D:  // 5 nav pad
        if ( iMode == 1 ){
          PrevCode = TV5PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08A8AD:  // 6 nav pad
        if ( iMode == 1 ){
          PrevCode = TV6PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08686D:  // 7 nav pad
        if ( iMode == 1 ){
          PrevCode = TV7PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08E8ED:  // 8 nav pad
        if ( iMode == 1 ){
          PrevCode = TV8PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08181D:  // 9 nav pad
        if ( iMode == 1 ){
          PrevCode = TV9PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      case 0xD08989D:  // 0 nav pad
        if ( iMode == 1 ){
          PrevCode = TV0PAD ;
          bTransmit = true ;
          bRepeat = false ;
        }
      break;
      default:
          bTransmit = false ;
          bRepeat = false ;
      break;
    }
    if ( bTransmit ){
      Serial.print("T ");
      Serial.println(PrevCode, HEX);
      irsend.sendNEC(PrevCode,32);    
      bTransmit = false ;
    }
    delay(50);
    irrecv.resume();              // Prepare for the next value
        
    irrecv.enableIRIn();            // Start the receiver
    irrecv.blink13(1);

  }

}
This is the ESP8266 - NodeMCU version of the code
This is very cool and useful widget.

Schematics

The ESP8266 version
Sorry... The tri-color LED is shown the wrong polarity
Simple Schematic

Comments

Team Trouble

Dougalplummer
DougalPlummer
  • 4 projects
  • 40 followers

Additional contributors

  • Beta testers - putting up with the tv changing volume lots over an interesting movie by Teresa, Annie Rae

Published on

April 22, 2019

Members who respect this project

PhotoSun wuk0ngDefaultMark05ProfilepicPic 20180807 102410642 a1vf6i4tjd

and 3 others

See similar projects
you might like

Similar projects you might like

WiFi IR Blaster

Project tutorial by BuddyC

  • 88,952 views
  • 43 comments
  • 93 respects

OH HAI! on Windows 10 IoT Core

Project in progress by BuddyC

  • 12,530 views
  • 3 comments
  • 48 respects

IoT arduino ESP Garage Door opener (UD)

Project in progress by David Smerkous

  • 11,969 views
  • 6 comments
  • 19 respects

IR Remote Controlled Home Automation

Project tutorial by suhail jr

  • 10,644 views
  • 7 comments
  • 19 respects

Amazon Echo (IR) TV Remote

Project showcase by LIMPINGLIM

  • 1,487 views
  • 3 comments
  • 7 respects
Add projectSign up / Login