About a year ago I needed the ability to control my Tivo S3 from another room. Originally I purchased some cheap IR Extender from Radio Shack and tried it. After toying around with it I knew that a off-shelf product was going to be useless.
So I developed my own solution:
After doing some reading I knew the Tivo S3/HD (newer ones probably as well) have a telnet server running on the Tivo that allows 3rd party apps to control the Tivo.
To test this, all you need to do is open a Telnet client, connect to your Tivo's IP using port 31339 and then you could start sending out commands to the Tivo like the following:
IRCODE TIVO
IRCODE LIVETV
IRCODE UP
With this in mind, I knew there was the ability to control the Tivo using an ethernet device.
Previously I had played around with Arduino . This is a microcontroller which you can program to control your I/O's on the device. This device also supports an Ethernet Sheild which would allow me to communicate with the Tivo's Telnet server. Next I needed a IR receiver for this to work, after Googling I found this receiver on SparkFun.
Here is the hardware:

Now comes the fun part: the software:
#include
#include
#include
#include
#include
#include
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = {
192, 168, 0, 213 }; // 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;
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 (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
// Serial.println("-----");
if (results.value == 0xFFFFFFFF) {
results = resultslast;
}
switch (results.value) {
case 0xA10CD00F: //Tivo Button (cheapo remote)
sndcmd("IRCODE TIVO");
break;
case 0xA10C500F: //Tivo Button (nice remote)
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
}
}
I used this IR library I found on the net from Ken Shirriff. Basically it has the ability to capture the keys pressed from the Tivo Remote and returns a integer (ex. 0xA10C4C03). Each button fires a different integer. With this I mapped out each command, then connect to the Tivo and pass the proper Telnet command.
Below you can find a YouTube video of the device in action: