A Raspberry Pi that wakes the media PC and switches the sockets
The media PC is now an Intel NUC, and the trouble with a PC that goes to sleep is waking it up again. An IR receiver on the NUC itself isn’t much use when the NUC is off and you want to turn it on! So I’ve given it a doorman: a Raspberry Pi that listens for the remote, and can switch the mains sockets too.
Teaching the Pi the remote
The Pi runs LIRC, which I last wrestled with for the HDMI-CEC remote bridge. Before LIRC can understand a remote, you have to teach it the codes with irrecord, which has you press every button in turn. My config dates back to 19 December 2013. It’s an RC5 remote, the old Philips protocol, with 45 buttons.
The only button the Pi acts on itself, for now, is power. LIRC’s irexec runs a command when a button is pressed, so the whole of my .lircrc is this:
begin
prog = irexec
button = KEY_POWER
repeat = 0
config = /home/pi/wake_nuc.sh
end
The script it calls is a one-liner that sends a wake-on-LAN “magic packet” to the NUC. That’s a special broadcast packet containing the network card’s MAC address repeated sixteen times. The NUC’s network card listens for it even while the rest of the machine is asleep, and switches the PC on when it hears it. So pressing power on the remote now wakes the NUC.
Switching the sockets
The other job is mains power. I have a set of remote-control sockets, the kind that come in a pack with a little 433 MHz key-fob remote. Mine are Status-branded: one is for a lamp, and the other turns on the amp. Like most cheap remotes of this sort, the fob doesn’t expect any reply. It just shouts a code and hopes someone’s listening. So a cheap 433 MHz transmitter module on one of the Pi’s GPIO pins can shout the same codes.
I wrote a little C++ program, using the wiringPi library, that takes a channel (1 to 4) and on or off, and sends the right frame. Each frame is 25 bits of on-off keying:
| bits | meaning |
|---|---|
| 0–19 | remote ID, the same for every button |
| 20–23 | which channel, and on or off |
| 24 | a final 0 |
A 0 is 300 µs of carrier then 900 µs of silence, and a 1 is the other way round, so a whole frame takes 30 ms. The four command bits are simply (channel − 1) × 2, plus one for “off”, sent backwards and upside down: lowest bit first, with every bit inverted. So channel 1 on is 1111, and channel 1 off is 0111. As for the remote ID, the one in my code is my fob’s own, so the example below uses a made-up one. I’d rather not have anyone switching our sockets on and off from the street.
10100101110010100110 0111 0 (made-up remote ID, channel 1, off)
The fiddly bit is timing. Linux isn’t a real-time operating system, and if the scheduler wanders off in the middle of a frame, the socket hears gibberish. My first attempts only worked some of the time, and working out that timing was the culprit was one of those head-scratchers. The fix is that the program:
- busy-waits on the monotonic clock instead of sleeping, because a sleeping program has handed control to the scheduler with no promise of getting it back on time;
- bumps itself up to real-time scheduling priority (
SCHED_FIFO) before it starts sending, so nothing else gets a look in for those 30 ms.
That means running it with sudo, which is fine for something this small.
It sends each frame just once. Remotes like this usually repeat the frame several times while you hold the button, so if a socket misses it, the fix is simply to run the program again.
Where it stands
The remote’s power button wakes the NUC, and any of the sockets can be switched from the Pi’s command line. The two don’t meet yet: the remote can’t switch the sockets.