Arduino Tivo IR Extender to Ethernet (telnet)

I thought I would share this project.

Let me explain the history of the project. I have one Tivo in the Living room which is connected to the TV using HDMI. Instead of buying another Tivo for the bedroom, I ran component cables to the bedroom from the Living room. Now I can watch the Tivo in the Living room/Bedroom.

Then I bought a 20$ IR Extenderhttp://www.radioshack.com/product/index.jsp?productId=2103599 from Radio Shack. The thing worked if lighting conditions were okay (dark room). When it was bright in the room, then the device didnt work. So in the end this IR Extender was junk.

That is what made me decide to build my own IR Extender. When I was going over how I was going to make this work; I realized that the Tivo supports a telnet protocol which allows you to basically simulate all the remote's buttons.

So I used a spare Arduino and bought the Ethernet Shield and a 38 kHz IR Receiver from Sparkfun. Once I had all the hardware, I started looking at how I can determine what button on the Tivo remote was pressed. Luckily I found a library which was able to generate a unique #/code that represented each button on the remote. Once I had this figured out I cross referenced the IR codes to the Tivo telnet protocol.

Now using the Arduino and the Ethernet shield I was able to capture what buttons I was pressing on my Tivo Remote and translate that to a telnet message that the Tivo can use.

Then it was time to build a enclosure for this project so I bought a 3$ project box from Radioshack and closed everything up.

Below are the pictures. I will post a YouTube video tomorrow when its bright outside :). Read below to see all the links.





The box has 2 LED's. Green means that the Power is on, and the Red glows when the Tivo is recording something. Again I will try to post a video tomorrow.

Sparkfun IR Receiver 38 kHz SparkFun IR Receiver Breakout - TSOP85 - SEN-08554 - SparkFun Electronics

Multi-Purpose IR Lib for Arduinohttp://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html

Tivo Telnet Explained http://tivocommunity.com/tivo-vb/showthread.php?t=392385

Here is the code. I know its not the cleanest code, but works :):

#include <IRremote.h>
#include <Ethernet.h>
#include <WString.h>

#define maxLength 30

String inString = String(maxLength);

byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = {
192, 168, 0, 212 }; // Device IP
byte server[] = {
192, 168, 0, 134 }; // Tivo

Client client(server, 31339);

int RECV_PIN = 3;
IRrecv irrecv(RECV_PIN);
decode_results results;
decode_results resultslast;
unsigned long firetime;
unsigned long lastreccheck;

void setup()
{
irrecv.enableIRIn(); // Start the receiver
Ethernet.begin(mac, ip);
//Serial.begin(9600);
pinMode(6, OUTPUT);
pinMode(5, OUTPUT);

}

void sndcmd(char data[]) {
resultslast = results;

if (millis() - firetime >= 150) {
if (client.connect()) {
client.println(data);
}
else
{
client.stop();
delay(50);
if (client.connect()) {
client.println(data);
}
}

firetime = millis();
}
}

void loop() {
analogWrite(5, 15);

if (client.available()) {
char c = client.read();
//Serial.print(c);

if (inString.length() < maxLength) {
inString.append(c);
}
else {
// empty the string by setting it equal to the inoming char:
inString = "";
}

lastreccheck = millis();
if (inString.contains("RECORD")) {
analogWrite(6,255);
//inString = "";
}
if (inString.contains("LOCAL")) {
analogWrite(6,0);
//inString = "";
}
if (inString.contains("REMOTE")) {
analogWrite(6,0);
//inString = "";
}

}

if (millis() - firetime > 10000) {
sndcmd("");
}

if (irrecv.decode(&results)) {

//Serial.println(results.value, HEX);
// Serial.println("-----");

if (results.value == 0xFFFFFFFF) {
results = resultslast;
}

switch (results.value) {

case 0xA10C500F: //Tivo Button
sndcmd("IRCODE TIVO");
break;

case 0xA10C8807: //LiveTV Button
sndcmd("IRCODE LIVETV");
break;

case 0xA10CC807: //Info Button
sndcmd("IRCODE DISPLAY");
break;

case 0xA10C6C03: //Guide Button
sndcmd("IRCODE GUIDE");
break;

case 0xA10C2807: //Select Up Button
sndcmd("IRCODE UP");
break;

case 0xA10C6807: //Select Down Button
sndcmd("IRCODE DOWN");
break;

case 0xA10CE807: //Select Left Button
sndcmd("IRCODE LEFT");
break;

case 0xA10CA807: //Select Right Button
sndcmd("IRCODE RIGHT");
break;

case 0xA10C9807: //Select Button
sndcmd("IRCODE SELECT");
break;

case 0xA10C1807: //Thumbs Down
sndcmd("IRCODE THUMBSDOWN");
break;

case 0xA10C5807: //Thumbs Up
sndcmd("IRCODE THUMBSUP");
break;

case 0xA10C7807: //Channel Up
sndcmd("IRCODE CHANNELUP");
break;

case 0xA10CF807: //Channel Down
sndcmd("IRCODE CHANNELDOWN");
break;

case 0xA10C040B: //Record
sndcmd("IRCODE RECORD");
break;

case 0xA10C840B: //Play
sndcmd("IRCODE PLAY");
break;

case 0xA10CC40B: //Pause
sndcmd("IRCODE PAUSE");
break;

case 0xA10CA40B: //Slow
sndcmd("IRCODE SLOW");
break;

case 0xA10C440B: //Reverse
sndcmd("IRCODE REVERSE");
break;

case 0xA10C240B: //Forward
sndcmd("IRCODE FORWARD");
break;

case 0xA10CE40B: //Advance
sndcmd("IRCODE ADVANCE");
break;

case 0xA10C640B: //Replay
sndcmd("IRCODE REPLAY");
break;

case 0xA10C140B: //Num 1
sndcmd("IRCODE NUM1");
break;

case 0xA10C940B: //Num 2
sndcmd("IRCODE NUM2");
break;

case 0xA10C540B: //Num 3
sndcmd("IRCODE NUM3");
break;

case 0xA10CD40B: //Num 4
sndcmd("IRCODE NUM4");
break;

case 0xA10C340B: //Num 5
sndcmd("IRCODE NUM5");
break;

case 0xA10CB40B: //Num 6
sndcmd("IRCODE NUM6");
break;

case 0xA10C740B: //Num 7
sndcmd("IRCODE NUM7");
break;

case 0xA10CF40B: //Num 8
sndcmd("IRCODE NUM8");
break;

case 0xA10C0C03: //Num 9
sndcmd("IRCODE NUM9");
break;

case 0xA10C8C03: //Num 0
sndcmd("IRCODE NUM0");
break;

case 0xA10CCC03: //Enter
sndcmd("IRCODE ENTER");
break;

case 0xA10C4C03: //Clear
sndcmd("IRCODE CLEAR");
break;

default:
resultslast = results;
break;

}

irrecv.resume(); // Receive the next value
}

}