Wednesday, April 23, 2014

IR Receiver extension for Ambilight raspberry pi clone

After working with my ambilight clone for a few days, I discovered the biggest annoyance was that it wouldn't turn off after turning off the TV.  I had some ideas on how I could remotely trigger it from the phone or from an external HTPC but I really wanted a self contained solution in case I decided to swap the HTPC for a FireTV or a Chromecast.

This brought me to trying to do it directly via my remote.  My HTPC uses a mceusb, so I was tempted to just get another mceusb for the pi.  This would have been overkill though, the pi has tons of unused GPIO's, it can be done far simpler (and cheaper).

I looked into it and discovered that someone actually already wrote a kernel module that directly controls an IR sensor on a GPIO.  The kernel module is based off the existing lirc_serial module, but adapted specifically for the raspberry pi.  (See http://aron.ws/projects/lirc_rpi/ for more information)

Hardware

All that's necessary is a 38 kHz IR sensor.  You'll spend under $5 on one of them on Amazon (plus some shipping) or you can get one from radio shack if you want something quick and local.  I spent $4.87 on one at my local radio shack.

The sensor is really simple, 3 pins.  All 3 pins are available in the pi's header.  One goes to 3.3V rail, one to ground, and one to a spare GPIO.  There's a few places on the header that you can use for each.  Just make sure you match up the pinout to the sensor you get.  I chose to use GPIO 22 as it's most convenient for my lego case.  The lirc_rpi defaults to GPIO 18.

Some notes to keep in mind:

  1. While soldering it, be cognizant of which way you want the sensor to face so that it can be accessed from the remote.  
  2. Remember that you are connecting to 3.3V and Ground from the Pi header.  The ground connection won't be the same as your rail that was used to power the pi if you are powering via USB.  
  3. The GPIO pins are not rated for 5V, so be sure to connect to the 3.3V.



Software


LIRC is available directly in the raspbian repositories.  Install it like this:

# sudo apt-get install lirc

Manually load the module so that you can test it.

# sudo modprobe lirc_rpi gpio_in_pin=22

Now use mode2 to test that it's working.  Once you run the command, press some buttons on your remote.  You should be output about space, pulse and other stuff.  Once you're satisfied, press ctrl-c to exit.

# mode2 -d /dev/lirc0

Now, add the modules that need to be loaded to /etc/modules.  If you are using a different GPIO than 18, specify it here again.  This will make sure that lirc_rpi loads on boot.

/etc/modules

lirc_dev
lirc_rpi gpio_in_pin=22


Now modify /etc/lirc/hardware.conf to match this configuration to make it work for the rpi:

/etc/lirc/hardware.conf

# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS="--uinput"

#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD=false

#Don't start irexec, even if a good config file seems to exist.
#START_IREXEC=false

#Try to load appropriate kernel modules
LOAD_MODULES=true

# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev 
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"

# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""

Next, we'll record the buttons that you want the pi to trigger the backlight toggle on.  I chose to do it on the event of turning the TV on or off.  For me I actually have a harmony remote that has separate events for "Power On" and "Power Off" available.  So I chose to program KEY_POWER and KEY_POWER2.  If you don't have the codes available for both "Power On" and "Power Off" then you can just program "Power Toggle" to KEY_POWER.

# irrecord -d /dev/lirc0 ~/lircd.conf

Once you have the lircd.conf recorded, move it into /etc/lirc to overwrite /etc/lirc/lircd.conf and start lirc

# sudo mv /home/pi/lircd.conf /etc/lirc/lircd.conf
# sudo /etc/init.d/lirc start

With lirc running you can examine that it's properly recognizing your key event using the irw command.  Once irw is running, press the button on the remote and make sure your pi recognizes it.  Once you're done press ctrl-c to exit.

# irw

Now that you've validated the pi can recognize the command, it's time to tie it to an actual script.  Create /home/pi/.lircrc with contents like this:

/home/pi/.lircrc

begin
     button = KEY_POWER
     prog = irexec
     repeat = 0
     config = /home/pi/toggle_backlight.sh off
end

begin
     button = KEY_POWER2
     prog = irexec
     repeat = 0
     config = /home/pi/toggle_backlight.sh on
end

My toggle_backlight.sh looks like this:

/home/pi/toggle_backlight.sh

#!/bin/sh
ARG=toggle
if [ -n "$1" ]; then
ARG=$1
fi
RUNNING=$(pgrep hyperion-v4l2)
if [ -n "$RUNNING" ]; then
if [ "$ARG" = "on" ]; then
exit 0
fi
pkill hyperion-v4l2
hyperion-remote --color black
exit 0
fi
if [ "$ARG" = "off" ]; then
hyperion-remote --color black
exit 0
fi
#spawn hyperion remote before actually clearing channels to prevent extra flickers
hyperion-v4l2 --crop-height 30 --crop-width 10 --size-decimator 8 --frame-decimator 2 --skip-reply --signal-threshold 0.08&
hyperion-remote --clearall


To test, run irexec and then press your remote button.  With any luck irexec will launch the toggle script and change your LED status.

# irexec

Lastly, you need to add irexec to your /etc/rc.local to make it boot with the pi.  Make sure you put the execution before the exit 0

/etc/rc.local

su pi -c "irexec -d"
su pi -c "/home/pi/toggle_backlight.sh off"

Reboot your pi, and make sure everything works together.  

# sudo reboot