Reading an IR Remote on a Raspberry Pi with LIRC
Our makerspace got some new Arduino kits that come with a bunch of fun parts I hadn't played with before, including an IR remote and receiver.
The kits are intended for Arduino and there are Arduino libraries to handle it, but I wanted to try it with a Raspberry Pi as well.
It turned out to be much trickier than I expected to read signals from the IR remote in Python on the Pi. There's plenty of discussion online, but most howtos are out of date and don't work, or else they assume you want to use your Pi as a media center and can't be adapted to more general purposes. So here's what I learned.
Update: this page is for Raspbian Jessie. If you've upgraded to Stretch, read the update, Reading an IR Remote on a Raspberry Pi Stretch with LIRC, then come back here and jump forward to Set up a lircd.conf.
Install LIRC and enable the drivers on the Pi
The LIRC package reads and decodes IR signals, so start there:
$ sudo apt-get install lirc python-lirc python3-lirc
Then you have to enable the lirc daemon. Assuming the sensor's pin is on the Pi's GPIO 18, edit /boot/config.txt as root, look for this line and uncomment it:
# Uncomment this to enable the lirc-rpi module dtoverlay=lirc-rpi
Reboot. Then use a program called mode2 to make sure you can read from the remote at all, after first making sure the lirc daemon isn't running:
$ sudo service lirc stop $ ps aux | grep lirc $ mode2 -d /dev/lirc0
Press a few keys. If you see a lot of output, you're good. If not, check your wiring.
Set up a lircd.conf
You'll need to make an lircd.conf file mapping the codes the buttons send to symbols like KEY_PLAY. You can do that -- ina somewhat slow and painstaking process -- with irrecord.
First you'll need a list of valid key names. Get that with
irrecord -l
and you'll probably want to keep that window up so you can search
or grep in it. Open another window and run:
$ irrecord -d /dev/lirc0 ~/lircd.conf
I had to repeat the command a couple of times; the first few times
it couldn't read anything. But once it's running, then for
each key on the remote, first, find the key name
that most closely matches what you want the key to do (for instance,
if the key is the power button, irrecord -l | grep -i power
will suggest KEY_POWER and KEY_POWER2). Type or paste that key name
into irrecord -d, then press the key.
At the end of this, you should have a ~/lircd.conf.
Some guides say to copy that lircd.conf to /etc/lirc/ andI did, but I'm not sure it matters if you're going to be running your programs as you rather than root.
Then enable the lirc daemon that you stopped back when you were testing with mode2. In /etc/lirc/hardware.conf, START_LIRCMD is commented out, so uncomment it. Then edit /etc/lirc/hardware.conf as specified in alexba.in's "Setting Up LIRC on the RaspberryPi". Now you can start the daemon:
sudo service lirc startand verify that it's running:
ps aux | grep lirc
.
Testing with irw
Now it's time to test your lircd.conf:
irwPress buttons, and hopefully you'll see lines like
0000000000fd8877 01 KEY_2 /home/pi/lircd.conf 0000000000fd08f7 00 KEY_1 /home/pi/lircd.conf 0000000000fd906f 00 KEY_VOLUMEDOWN /home/pi/lircd.conf 0000000000fd906f 01 KEY_VOLUMEDOWN /home/pi/lircd.conf 0000000000fda05f 00 KEY_PLAYPAUSE /home/pi/lircd.conf
If they correspond to the buttons you pressed, your lircd.conf is working.
Reading Button Presses from Python
Now, most tutorials move on to generating a .lircrc file which sets up your machine to execute programs automatically when buttons are pressed, and then you can test with ircat. If you're setting up your Raspberry Pi as a media control center, that's probably what you want (see below for hints if that's your goal). But neither .ircrc nor ircat did anything useful for me, and executing programs is overkill if you just want to read keys from Python.
Python has modules for everything, right? The Raspbian repos have python-lirc, python-pylirc and python3-lirc, and pip has a couple of additional options. But none of the packages I tried actually worked. They all seem to be aimed at setting up media centers and wanted lircrc files without specifying what they need from those files. Even when I set up a .lircrc they didn't work. For instance, in python-lirc, lirc.nextcode() always returned an empty list, [].
I didn't want any of the "execute a program" crap that a .lircrc implies. All I wanted to do was read key symbols one after another -- basically what irw does. So I looked at the irw.c code to see what it did, and it's remarkably simple. It opens a socket and reads from it. So I tried implementing that in Python, and it worked fine: pyirw.py: Read LIRC button input from Python.
While initially debugging, I still saw those
0000000000fda05f 00 KEY_PLAYPAUSE /home/pi/lircd.conflines printed on the terminal, but after a reboot they went away, so they might have been an artifact of running irw.
If You Do Want a .lircrc ...
As I mentioned, you don't need a .lircrc just to read keys from the daemon. But if you do want a .lircrc because you're running some sort of media center, I did find two ways of generating one.
There's a bash script called lirc-config-tool floating around that can generate .lircrc files. It's supposed to be included in the lirc package, but for some reason Raspbian's lirc package omits it. You can find and download the bash script witha web search for lirc-config-tool source, and it works fine on Raspbian. It generates a bunch of .lircrc files that correspond to various possible uses of the remote: for instance, you'll get an mplayer.lircrc, a mythtv.lircrc, a vlc.lircrc and so on.
But all those lircrc files lirc-config-tool generates use only
small subsets of the keys on my remote, and I wanted one that included
everything. So I wrote a quickie script called
gen-lircrc.py
that takes your lircd.conf as input and generates a
simple lircrc containing all the buttons represented there.
I wrote it to run a program called "beep" because I was trying to
determine if LIRC was doing anything in response to the lircrc (it
wasn't); obviously, you should edit the generated .lircrc and
change the prog = beep
to call your target programs instead.
Once you have a .lircrc, I'm not sure how you get lircd to use it to call those programs. That's left as an exercise for the reader.
[ 11:21 Oct 26, 2017 More hardware | permalink to this entry | ]