Shallow Thoughts : tags : remote

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Sun, 26 Nov 2017

Reading an IR Remote on a Raspberry Pi Stretch with LIRC

I wrote earlier about how to use an IR remote on Raspbian Jessie.

It turns out several things have changed under Raspbian Stretch.

Update, August 2019:
Apparently these updated instructions don't work any more either. What apparently works now:

In /boot/config.txt, add:

dtoverlay=gpio-ir,gpio_pin=18

In /etc/lirc/lirc_options.conf, add:

driver=default
device = /dev/lirc0

/etc/modules and /etc/lirc/hardware.conf/ don't need to be changed. Thanks to Sublim21 on #raspberrypi for the tip.

Here's the older procedure and discussion.

Here's the abbreviated procedure for Stretch:

Install LIRC

$ sudo apt-get install lirc

Enable the LIRC Overlay

Eedit /boot/config.txt as root, look for this line and uncomment it:

# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi
Or if you prefer to use a pin other than 18, change the pin assignment like this:
# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi,gpio_in_pin=25,gpio_out_pin=17

See /boot/overlays/README for more information on overlays.

Fix the LIRC Options

Edit /etc/lirc/lirc_options.conf, comment out the existing driver and device lines, and add:

driver    = default
device = /dev/lirc0

Reboot and stop the daemon

Reboot the Pi.

Now a bunch of LIRC daemons will be running. You don't want them while you're configuring, and if you're eventually going to be reading button presses from Python, you don't want them at all.

Disable them temporarily with

sudo systemctl stop lircd
which seems to be shorthand for
sudo systemctl stop lircd.socket
sudo systemctl stop lircd.service

Be sure to check with ps aux | grep lirc to make sure you've turned them off.

If you want to disable them permanently,

sudo systemctl disable lircd.socket lircd.service lircd-setup.service lircd-uinput.service lircmd.service
I got that list from:
systemctl list-unit-files | grep lirc

But you need them if you want to read from the /var/run/lirc/lircd socket.

Use mode2 to verify it sees the buttons

With the daemons not running, a program called mode2 can verify that your device's buttons are being seen at all. I have no idea why it's named that, or what Mode 1 is.
mode2 -d /dev/lirc0

You should see lots of output. If you don't, double-check your wiring and everything else you've done up to now.

Set up an lircd.conf

Here's where it gets difficult. On Jessie, you could run irrecord -d /dev/lirc0 ~/lircd.conf as described in my earlier article.

However, that doesn't work on stretch. There's apparently a bug in the irrecord in stretch that makes it generate a file that doesn't work. If you try it and it doesn't work, run tail -f /var/log/messages | grep lirc and you may see Info: Cannot configure the rc device for /dev/lirc0 and when you press buttons you'll see Notice: repeat code without last_code received but you won't get any keys.

If you have a working lirc setup from a Jessie machine, try it first. If it doesn't work, there's a script you can try that converts older lirc conf files to a newer format. The safest way to try it is to copy (with cp -a) the whole /etc/lirc directory to a local directory and run:

/usr/share/lirc/lirc-old2new your-local-copy
Or if you feel brave, back up /etc/lirc and run sudo /usr/share/lirc/lirc-old2new with no arguments. Either way, you should get an lirc.conf that has a chance of working with stretch.

If you don't have a working Jessie config, you're in trouble. You might be able to edit the one from irrecord to make it work. Here's the first part of my working Jessie lircd.conf:

begin remote

  name  /home/pi/lircd.conf
  bits           16
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100

  header       9117  4494
  one           569  1703
  zero          569   568
  ptrail        575
  repeat       9110  2225
  pre_data_bits   16
  pre_data       0xFD
  gap          108337
  toggle_bit_mask 0x0

      begin codes
          KEY_POWER                0x00FF
          KEY_VOLUMEUP             0x807F
          KEY_STOP                 0x40BF
          KEY_BACK                 0x20DF
          KEY_PLAYPAUSE            0xA05F
          KEY_FORWARD              0x609F
          KEY_DOWN                 0x10EF
and here's the corresponding part of the nonworking one generated on Stretch:
begin remote

  name  DingMai
  bits           32
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100

  header       9117  4494
  one           569  1703
  zero          569   568
  ptrail        575
  repeat       9110  2225
  gap          108337
  toggle_bit_mask 0x0
  frequency    38000

      begin codes
          KEY_POWER                0x00FD00FF 0xBED8F1BC
          KEY_VOLUMEUP             0x00FD807F 0xBED8F1BC
          KEY_STOP                 0x00FD40BF 0xBED8F1BC
          KEY_BACK                 0x00FD20DF 0xBED8F1BC
          KEY_PLAYPAUSE            0x00FDA05F 0xBED8F1BC
          KEY_FORWARD              0x00FD609F 0xBED8F1BC
          KEY_DOWN                 0x00FD10EF 0xBED8F1BC

It looks like setting bits to 16 and then using the second quartet from each key might work. So try that if you're stuck.

Once you get irw working, you're home free. The Python modules probably still won't do anything useful, but you can use my pyirw.py script as a model for a simple way to read keys from the lirc daemon.

In case you hit problems beyond what I saw, I found this discussion useful, which links to a complete GitHub gist of instructions for setting up lirc on Stretch. Those instructions have a couple of extra steps involving module loading that it turned out I didn't need, and on the other hand it doesn't address the problems I saw with irrecord. It looks like lirc configuration is a black art, not a science. See what works for you. Good luck!

Tags: , ,
[ 12:00 Nov 26, 2017    More hardware | permalink to this entry | ]

Thu, 26 Oct 2017

Reading an IR Remote on a Raspberry Pi with LIRC

[IR remote with Raspberry Pi Zero W]

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 start
and verify that it's running: ps aux | grep lirc.

Testing with irw

Now it's time to test your lircd.conf:

irw
Press 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.conf
lines 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.

Tags: , ,
[ 11:21 Oct 26, 2017    More hardware | permalink to this entry | ]