The musings of a dilettante on parenting, mechanics, philosophy and the background noise that is daily life. From beautiful ruralburbian Philomath, Oregon.
My bench went through several different messes.
The trundle bed I was assembling had an unthreaded nut. No problem to tap it, but normal people would have been annoyed.
A sunny day at the Oregon coast.
Children playing in the sand.
A tiny landslide.
Brothers.
Hannah, Felice and Anne.
I like taking pictures of people taking pictures, Eric.
I also like taking pictures when people aren’t posing correctly.
Henry noticed something hanging above the gate to the driveway…
A bald faced hornet’s nest…yikes!!!! Jim DiGiulio will be coming to vacuum it up.
UPDATE! See end of post for code change made on 08/04/11
With the circuit working al I needed to do was install it on the HTPC…
For power I could have grafted into the ATX power supply wires as Simerec does (PDF) but I found that the Biostar A780L3L motherboard I used in the HTPC could supply standby power to the USB ports by moving a jumper. This is obviously much easier. Another alternative is to use a powered USB hub to power the Teensy when the PC is off. Notice the yellow power cord attached to the motherboard as well.
The HTPC pulled apart for testing, as you can see from the TV, the PC is on.
Satisfied that it all works, I set to work duplicating the circuit on a prototyping perfboard from Radioshack. Note that I have a couple of Teensy-s. $16.00 each is so cheap for what they can do.
I soldered pins to the Teensy (for $3.00 they will do it for you…) and soldered headers to the perfboard.
Soldering…I am still learning this skill.
Slowly moving everything over. Note I had to re-label the perfboard as I didn’t pay attention and had it backwards…
All done. Please don’t make fun of my poor layout.
Testing again. Such a mess in my shop.
The last item was a “Y” cable for the power switch so I could either power on the PC with the switch or the remote. I used some ethernet twisted pair wires.
I needed a male pin.
Bent…
Soldered and heat shrink to insulate the wires from each other.
Then some heat shrink over that to stiffen it up.
The finished cable.
I mounted the board on a piece of aluminum. This is semi-temporary until I figure out an enclosure. I’m thinking a transparent plastic box.
Set up on top of the HTPC. I could mount it inside the empty 5.25” bay, but I want to leave it out. I can change things, easily reprogram, etc. as well as having a monument to my poor layout and soldering skills.
The power cable snakes in through a vent in the side.
Now I just turn the PC on while laying ensconced in the comfort of my bed. It’s a lot of work being lazy.
I added some functionality to the code. The remote also emulates the arrow keys, enter key, mouse (R/L, U/D only), right and left mouse buttons, scroll wheel, CTRL++ and CTRL—for screen magnification in Internet Explorer (and other browsers), it will also launch Internet Explorer directly into Hulu, launch Media Center, Media Player. I still have a few buttons left over.
Here’s the code as it stands right now:
#include <IRremote.h>
const int RECV_PIN = 6; // pin that the IR receiver is on
IRrecv irrecv(RECV_PIN); // receive IR on that pin
decode_results results; // the code sent by the remote
int relayPin = 1; // pin out for relay pin and LED
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
pinMode(relayPin, OUTPUT); // set the pin for the relay.
digitalWrite(relayPin, LOW); // turn off the relay.
}
void loop() { // main program loop
if (irrecv.decode(&results)) { // if a result is received, put it in results
if (results.value != 0) { //this prints the remote value to the serial monitor if value received.
Serial.println(results.value); // print to serial monitor
delay(25); // 25ms delay. This can probably be decreased to 16ms per 62.5kps, but I don't know if I want it polling constantly?
}
if (results.value == 332 results.value == 2380) { // Power button pressed
digitalWrite(relayPin, HIGH); // actuate the relay to turn on or off power
delay(500); // waits for a second
digitalWrite(relayPin, LOW); // stop relay
delay(10000); // waits for 10 seconds, seems like more.
}
if (results.value == 2421 results.value == 373) { // Play, UP arrow
Keyboard.set_key1(KEY_UP); // set key up arrow
Keyboard.send_now(); //send up arrow
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
}
if (results.value == 2422 results.value == 374) { // stop, DOWN arrow
Keyboard.set_key1(KEY_DOWN); // set key down arrow
Keyboard.send_now(); //send up arrow
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
}
if (results.value == 2418 results.value == 370) { // rew left arrow
Keyboard.set_key1(KEY_LEFT); // set key left arrow
Keyboard.send_now(); //send left arrow
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
}
if (results.value == 2420 results.value == 372) { // FFWD right arrow
Keyboard.set_key1(KEY_RIGHT); // set key right arrow
Keyboard.send_now(); //send right arrow
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
}
if (results.value == 2397 results.value == 349) { // menu open IE with HULU
Keyboard.set_modifier(MODIFIERKEY_GUI); // winkey
Keyboard.send_now(); //send keypress
Keyboard.set_key1(KEY_R); // winkey+r
Keyboard.send_now(); //send send keypress
Keyboard.set_modifier(0); // set winkey key blank
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
delay(100); // 100ms delay. seems to work.
Keyboard.println("iexplore www.hulu.com"); // enter that in the run box as a line "ln"
}
if (results.value == 2417 results.value == 369) { // clear open media player.
Keyboard.set_modifier(MODIFIERKEY_GUI); // winkey
Keyboard.send_now(); //send keypress
Keyboard.set_key1(KEY_R); // winkey+r
Keyboard.send_now(); //send send keypress
Keyboard.set_modifier(0); // set winkey key blank
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
delay(100); // 100ms delay. seems to work.
Keyboard.println("wmplayer"); // enter that in the run box as a line "ln"
delay(100); // 100ms delay. seems to work.
}
if (results.value == 2383 results.value == 335) { // status/exit hit enter!
Keyboard.set_key1(KEY_ENTER); // enter
Keyboard.send_now(); //send send keypress
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
}
//mouse! A very slow and annoying mouse...
if (results.value == 2370 results.value == 322) { // 2 up
Mouse.move(0, -10);
}
if (results.value == 2376 results.value == 328) { // 8 down
Mouse.move(0, 10);
}
if (results.value == 2372 results.value == 324) { // 4 left
Mouse.move(-10, 0);
}
if (results.value == 2374 results.value == 326) { // 6 right
Mouse.move(10, 0);
}
if (results.value == 2369 results.value == 321) { // 1 left click
Mouse.set_buttons(1, 0, 0);
Mouse.set_buttons(0, 0, 0);
delay(100); // 100ms delay. seems to work.
}
if (results.value == 2371 results.value == 323) { // 3 right click
Mouse.set_buttons(0, 0, 1);
Mouse.set_buttons(0, 0, 0);
delay(100); // 100ms delay. seems to work.
}
if (results.value == 2400 results.value == 352) { // ch up scroll up
Mouse.scroll(3);
}
if (results.value == 2401 results.value == 353) { // ch down scroll down
Mouse.scroll(-3);
}
//end mouse!
if (results.value == 2423 results.value == 375) { // rec/otr opens media center, somewhat convoluted
Keyboard.set_modifier(MODIFIERKEY_GUI); // winkey
Keyboard.send_now(); //send keypress
Keyboard.set_key1(KEY_R); // winkey+r
Keyboard.send_now(); //send send keypress
Keyboard.set_modifier(0); // set winkey key blank
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
delay(100); // 100ms delay. seems to work.
Keyboard.print("%windir%"); // enter that in the run box as a line "ln"
Keyboard.set_key1(KEY_BACKSLASH); // backslash
Keyboard.send_now(); //send send keypress
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
Keyboard.print("ehome"); // enter that in the run box as a line "ln"
Keyboard.set_key1(KEY_BACKSLASH); // backslash
Keyboard.send_now(); //send send keypress
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
Keyboard.println("ehshell.exe"); // enter that in the run box as a line "ln"
delay(100); // 100ms delay. seems to work.
}
if (results.value == 2426 results.value == 378) { // speed ctrl-- size
Keyboard.set_modifier(MODIFIERKEY_CTRL); // ctrl
Keyboard.send_now(); //send keypress
Keyboard.set_key1(KEY_MINUS); // - key
Keyboard.send_now(); //send keypress
Keyboard.send_now(); //send keypress second time
Keyboard.set_modifier(0); // set ctrl key blank
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
delay(100); // 100ms delay. seems to work.
}
if (results.value == 2409 results.value == 361) { // still/pause ctrl++ size
Keyboard.set_modifier(MODIFIERKEY_CTRL); // ctrl
Keyboard.send_now(); //send keypress
Keyboard.set_key1(KEYPAD_PLUS); // + key
Keyboard.send_now(); //send keypress
Keyboard.send_now(); //send keypress second time
Keyboard.set_modifier(0); // set ctrl key blank
Keyboard.set_key1(0); // set key blank
Keyboard.send_now(); // release key
delay(100); // 100ms delay. seems to work.
}
irrecv.resume(); // Receive the next value
}
}
This keyboard and mouse emulation can be used for projects like the Awesome Button or something more evil like the Rubber Ducky. The Hak5 Rubber Ducky project is where I first heard of the Teensy. This same circuit could be used for all sorts of automation and/or practical jokes. I love the Teensy.
EDIT 08/04/11
I found that the remote wasn't working every day or so. I spent some time puzzling over this, testing all the wiring, but couldn't find a solution. Then it occurred to me that I was writing to the serial monitor every time it received an IR code. This could somehow fill whatever output buffer it has up. I was unable to find any reference to a problem like this, and it still may not be the problem, but commenting out this line:
Serial.println(results.value); // print to serial monitor
seems to have fixed the problem and I have not had a similar failure to communicate. Checking what other remotes were picked up, it seems as though the Roku remote puts out a very large number each keypress, I forget exactly but at least 6 or 7 digits. I often press the Roku buttons 20 or 30 times when surfing at night. So that's a lot of data that might have been piling up. Or not. I'll keep an eye on the problem over time. (As of 08/16 it's working perfectly!)
My friends know that I am an incredibly lazy person. So lazy that one of my irritations is that the HTPC (Home Theater PC) in the bedroom requires that I actually get up out of bed to turn it on. This is fine if I remember to switch it on before getting into bed, but most of the time I only remember after I have swaddled myself in blankets.
The solution of course is to have a way to use a remote control of some sort to turn on the PC. The first option is to not shut down the PC at all, but leave it in “sleep” mode. This is probably the most sensible option and I believe that I could set it up so a key press from my beloved IOGear wireless keyboard would accomplish it. But I don’t like sleep mode. I like computers to either be on or off. I’m cranky and old fashioned.
So how then to power on a PC remotely? There are again a couple of options. I could use Wake Over LAN to start it with the laptop I keep on the bedside table (roll your eyes). I could use a PS2 keyboard or mouse to power it on remotely, which would entail some wires strewn across the floor. I tried to get the USB wireless keyboard to power it on but was unsuccessful. Possibly I should have tried harder, but I wanted to try something different.
So my option is an IR remote controlled power switch. The nice folks at Simerec will sell you a kit or assembled IR remote power switch for the PC for about $30.00. This is probably the best option so you should just stop reading this post now and head on over there and order one.
You’re still here? Fine, don’t say I didn’t warn you. I did not buy the Simerec switch because I’m somewhat cheap (although in the end this project has cost 10 times that amount as it has spurred on new-hobby-buying-syndrome). I also was fresh from the high of Henry and my Awesome Button project and thought that a Teensy would fit the bill.
The Teensy can use Ken Shirriff’sIR remote library to receive and transmit IR remote control signals. So all I needed was to get an IR receiver and remote, figure out how to wire it up to receive input, figure out how to wire a relay to turn the PC power switch on, and program the thing. Easy! It will practically make itself!
So where to get the IR remote components? Well I happened to have several VCR’s laying around in case the sole surviving unit breaks (not that the kids have watched any VHS movies in the past year). So I decided to take one apart…This was too much fun to take pictures of. I was able to use my Edsyn solder suckerthat I bought a few years ago at the thrift store “because it looked handy”, to remove the IR receiver and a whole bunch of other useful bits.
The VCR bits. All non electronics went in the trash, anything left over from this pile will go to the electronics recycling dumpster be hoarded.
The bonus was a pile of little clicky switches. Those cost about 20 cents a piece! Awesome. Plus some other stuff I might use.
The Teensy on a breadboard with the IR receiver and a LED wired up to let me know if the power button is being pressed.
Another view. I wasn’t sure whether I should leave that shielding on the IR receiver.
The receiver gets power from the Teensy on one pin, the other is hooked to ground and the middle one is hooked to an input pin.
This is what the code looks like:
#include <IRremote.h>
const int RECV_PIN = 6; // pin that the IR receiver is on
IRrecv irrecv(RECV_PIN); // receive IR on that pin
decode_results results; // the code sent by the remote
int relayPin = 1; // pin out for relay pin and LED
void setup() { Serial.begin(9600); irrecv.enableIRIn(); // Start the receiver irrecv.blink13(true);
if (results.value != 0) { Serial.println(results.value); }
if (results.value == 332 results.value == 2380) { Serial.println("power"); digitalWrite(relayPin, HIGH); delay(1000); // waits for a second digitalWrite(relayPin, LOW); delay(10000); // waits for 10 seconds }
irrecv.resume(); // Receive the next value }
}
The code is simple and I’m not going to go into great detail about it but basically it starts the receiver, then in the main loop sees if a button press has been received. If the press is received it prints that value to the serial monitor (which makes it easy to decode each button as it is pressed). If the code received is either 332 or 2380 then the power switch has been pressed. You can look into IR protocols and learn more if you want. It is fascinating. If the power switch has been pressed then it sets the relay pin high for one second, then turns it off and waits ten seconds before resuming the loop. I did this to prevent accidentally turning it on and off in rapid succession.
Here are two short, grainy and boring videos of my turning the LED on and off as well as fading it (not applicable to this project, but neat nonetheless).
Next I had to figure out how to run a relay. Apparently with relays you need to protect the actuating circuit from the collapse of the coil field (snore…) which dumps a ton of voltage the wrong way ‘round into your circuit. This would be bad. So I found a schematic (PDF) that showed the parts I needed to avoid the problem.
LED off…
LED on…The button is mimicking the 5V signal from the Teensy. The LED is standing in for the PC power switch.
It’s a simple circuit. The 1N4005 diode was scavenged from the VCR. My suffering mentor (Thanks Gregg!) told me that a 1N4005 would work as well as a 1N4004.