Configure an infrared remote control with Linux

 Reading time ~9 minutes

Heads up: this article is over a year old. Some information might be out of date, as I don't always update older articles.

Introduction

Recently I bought a shiny new Intel NUC8i7HNK, equipped with 16 GB of RAM and a 500 GB SSD and I installed Ubuntu 18.04 LTS. I have to say that it works smoothly and my overall experience with it is really positive this far. I don’t really miss the MAC or Windows at all.

The Intel NUC8i7HNK comes with many different expansion options and among these, there is a front consumer infrared (CIR) sensor, so I asked myself if it was possible to control the NUC with a standard TV remote control.

Turns out that it’s possible and it’s also really easy, once you get to know how everyting works under the hood. This is my attempt to clarify the steps that I made to make it all work. They may be different for your cases, but they can be taken as a good starting point.

Warning: some of these information are quite technical and require some level of expertise. Proceed at your own risk.

First steps

First thing you need to check that the IR sensor is enabled in the BIOS. After turning on the computer press F2 (or any other key that you use to enter the BIOS) and check the menu to find the status of the IR sensor. Save your changes and exit.

Most of the guides available on the Internet suggest to install LIRC (Linux Infrared remote control), which is an open source package that allows users to receive and send infrared signals with a Linux-based computer system. That was also my first attempt, but I was unable to make it work following the documentation.

“LIRC is an old style linux application which can be tweaked to do almost anything, but is tricky to setup.”

Yeah I noticed! Thank you very much.

For reference, these were my steps:

  • Check if the IR sensor is enabled and active by inspecting the kernel messages using dmesg utility
$ dmesg | grep -i cir
[   34.095165] ite_cir: Auto-detected model: ITE8708 CIR transceiver
[   34.095167] ite_cir: Using model: ITE8708 CIR transceiver
[   34.095167] ite_cir: TX-capable: 1
[   34.095168] ite_cir: Sample period (ns): 8680
[   34.095168] ite_cir: TX carrier frequency (Hz): 38000
[   34.095169] ite_cir: TX duty cycle (%): 33
[   34.095169] ite_cir: RX low carrier frequency (Hz): 0
[   34.095170] ite_cir: RX high carrier frequency (Hz): 0
[   34.172171] rc rc0: ITE8708 CIR transceiver as /devices/virtual/rc/rc0
[   34.172206] input: ITE8708 CIR transceiver as /devices/virtual/rc/rc0/input17
[   34.172298] rc rc0: lirc_dev: driver ite-cir registered at minor = 0, raw IR receiver, raw IR transmitter
[   34.172890] ite_cir: driver has been successfully loaded

As you can see the sensor is working and it’s registered with the kernel.

  • Check the number of supported devices. This should list a single entry rc0.
$ ls /sys/class/rc
rc0
  • Invoke ir-keytable to see what receiver it recognizes and what protocols it supports
# Install ir-keytable if you don't have it already
$ sudo apt-get install ir-keytable
$ ir-keytable
Found /sys/class/rc/rc0/ (/dev/input/event9) with:
    Name: ITE8708 CIR transceiver
    Driver: ite-cir, table: rc-rc6-mce
    lirc device: /dev/lirc0
    Supported protocols: other lirc rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp
    Enabled protocols: lirc rc-6
    Extra capabilities: <access denied>

Quoting the lirc documentation:

“If you get this kind of output you know the event device (/dev/input/event9) and the kernel module loaded (ite-cir). Furthermore, since ir-keytable finds the device you know that the driver is part of the rc subsystem.”

For what concernes the protocols, we can see that the receiver supports most of them:

  • RC5 and RC6 are the IR protocols defined by Philips
  • Sharp use in VCRs that are produced by Sharp
  • NEC, or “Japanese Format”
  • Sony
  • JVC
  • XMP

Most remotes use the NEC protocol, including my old United LCD TV remote control.

$ sudo apt-get install lirc

During the install process I should have seen a configuration window, but that was not the case. Even running the command

$ sudo dpkg-reconfigure lirc

didn’t work out. Following the documentation I tried to manually configure the device and the driver using variations of the following command, to get the kernel output available for lirc drivers

$ mode2 --driver default --device auto

But it didn’t show anything. I also tried to cat into the device

$ cat /dev/input/event9

and pressing buttons on the remote should have printed something, but this was not the case.

Further discoveries

Later I discovered that there is an annoying bug on Ubuntu 18.04 that prevents lirc configuration during the installation process. A workaround is explained on this blog, but basically involves installing a previous version of lirc from Ubuntu 16.04 packages. It worked for me and I was able to see the configuration screen, but in the end the outcome was the same: I couldn’t see the signals from the IR sensor.

The revelation

In the end I should have read the lirc documentation more carefully, as it states clearly

Recent Linux kernels have built-in support for IR remotes. Using that, pressing an up-arrow on the remote works the same way as pressing the up-arrow on a keyboard.

So basically it should be possible to make IR work also without lirc, using kernel-specific drivers.

Second attempt

The following are the steps that lead me to successfully configure the remote controller on Ubuntu 18.04 LTS:

  • Remove lirc entirely from your system
$ sudo apt-get purge lirc

# If the /etc/lirc folder exists on your system, remove that as well
$ sudo rm -rf /etc/lirc
  • List supported remotes
$ ls /lib/udev/rc_keymaps/

If your remote control appears in this list, great! You can immediately use it. Otherwise you will have to test out which protocol uses the remote control, by enabling all of them and testing out.

$ sudo ir-keytable -v -t -p rc-5,rc-5-sz,jvc,sony,nec,sanyo,mce_kbd,rc-6,sharp,xmp
Found device /sys/class/rc/rc0/
Parsing uevent /sys/class/rc/rc0/lirc0/uevent
/sys/class/rc/rc0/lirc0/uevent uevent MAJOR=237
/sys/class/rc/rc0/lirc0/uevent uevent MINOR=0
/sys/class/rc/rc0/lirc0/uevent uevent DEVNAME=lirc0
Input sysfs node is /sys/class/rc/rc0/input17/
Event sysfs node is /sys/class/rc/rc0/input17/event9/
Parsing uevent /sys/class/rc/rc0/input17/event9/uevent
/sys/class/rc/rc0/input17/event9/uevent uevent MAJOR=13
/sys/class/rc/rc0/input17/event9/uevent uevent MINOR=73
/sys/class/rc/rc0/input17/event9/uevent uevent DEVNAME=input/event9
Parsing uevent /sys/class/rc/rc0/uevent
/sys/class/rc/rc0/uevent uevent NAME=rc-rc6-mce
/sys/class/rc/rc0/uevent uevent DRV_NAME=ite-cir
/sys/class/rc/rc0/uevent uevent DEV_NAME=ITE8708 CIR transceiver
input device is /dev/input/event9
/sys/class/rc/rc0/protocols protocol rc-5 (disabled)
/sys/class/rc/rc0/protocols protocol nec (disabled)
/sys/class/rc/rc0/protocols protocol rc-6 (enabled)
/sys/class/rc/rc0/protocols protocol jvc (disabled)
/sys/class/rc/rc0/protocols protocol sony (disabled)
/sys/class/rc/rc0/protocols protocol rc-5-sz (disabled)
/sys/class/rc/rc0/protocols protocol sanyo (disabled)
/sys/class/rc/rc0/protocols protocol sharp (disabled)
/sys/class/rc/rc0/protocols protocol mce_kbd (disabled)
/sys/class/rc/rc0/protocols protocol xmp (disabled)
/sys/class/rc/rc0/protocols protocol imon (disabled)
/sys/class/rc/rc0/protocols protocol lirc (enabled)
Opening /dev/input/event9
Input Protocol version: 0x00010001
Protocols changed to rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp
Testing events. Please, press CTRL-C to abort.

By pressing the buttons on your remote you should see the received codes (scancode) and the protocol supported (nec)

20025.663892: lirc protocol(nec): scancode = 0x4001
20025.663912: event type EV_MSC(0x04): scancode = 0x4001
20025.663912: event type EV_SYN(0x00).

If you cannot see the name of the button (the usually are prefixed with KEY_, like KEY_1, KEY_VULUMEUP, etc.) the decode table doesn’t support the remote control. In this case you can easily check if one of the available remotes has the scancode:

$ grep -iH '0x4001' /lib/udev/rc_keymaps/*

If the search doesn’t return any results you should manually create the mapping between the scan code and the key. This will be as easy as writing a txt file with two columns. First you need to write down all the scan codes of your remote control, by pressing the buttons in order. Then you will need to map them to the available keys. The list is visible by using the following command:

$ irrecord -l

You probably don’t have this command, as it is a lirc dependency. You can still check the list online, for example at this link.

Go ahead and create a mapping by creating a new text file. Mine looks like this (make sure to include also the first line, by writing your protocol after type)

# table united, type: nec
0x4012  KEY_POWER
0x4016  KEY_INFO
0x4010  KEY_MUTE
0x4001  KEY_1
0x4002  KEY_2
0x4003  KEY_3
0x4004  KEY_4
0x4005  KEY_5
0x4006  KEY_6
0x4007  KEY_7
0x4008  KEY_8
0x4009  KEY_9
0x4000  KEY_0
0x4014  KEY_AUX
0x4052  KEY_AUDIO
0x405b  KEY_CONTROLPANEL
0x4044  KEY_EXIT
0x4019  KEY_UP
0x4047  KEY_RIGHT
0x401d  KEY_DOWN
0x4046  KEY_LEFT
0x400a  KEY_ENTER
0x401b  KEY_CHANNELUP
0x401f  KEY_CHANNELDOWN
0x405e  KEY_HOME
0x4018  KEY_COMPUTER
0x401a  KEY_VOLUMEUP
0x401e  KEY_VOLUMEDOWN
0x4042  KEY_WAKEUP
0x400d  KEY_SLEEP
0x4049  KEY_SEARCH
0x4040  KEY_REFRESH
0x4048  KEY_RED
0x404f  KEY_GREEN
0x4050  KEY_YELLOW
0x404b  KEY_BLUE

You can save the file wherever you want, but I suggest you to use the /etc/rc_keymaps location. Finally instruct ir-keytable to use the new mapping:

  • Delete the existing table
$ ir-keytable -c
  • load the new table from local file
$ sudo ir-keytable -c -p nec -w /etc/rc_keymaps/united
Read united table
Old keytable cleared
Wrote 36 keycode(s) to driver
Protocols changed to nec
  • check if the table is really there
$ ir-keytable -r
scancode 0x4000 = KEY_0 (0x0b)
scancode 0x4001 = KEY_1 (0x02)
scancode 0x4002 = KEY_2 (0x03)
scancode 0x4003 = KEY_3 (0x04)
scancode 0x4004 = KEY_4 (0x05)
scancode 0x4005 = KEY_5 (0x06)
scancode 0x4006 = KEY_6 (0x07)
scancode 0x4007 = KEY_7 (0x08)
scancode 0x4008 = KEY_8 (0x09)
scancode 0x4009 = KEY_9 (0x0a)
[...]
Enabled protocols: lirc nec
  • test the file
$ sudo ir-keytable -v -t -p nec
Found device /sys/class/rc/rc0/
Parsing uevent /sys/class/rc/rc0/lirc0/uevent
/sys/class/rc/rc0/lirc0/uevent uevent MAJOR=237
/sys/class/rc/rc0/lirc0/uevent uevent MINOR=0
/sys/class/rc/rc0/lirc0/uevent uevent DEVNAME=lirc0
Input sysfs node is /sys/class/rc/rc0/input17/
Event sysfs node is /sys/class/rc/rc0/input17/event9/
Parsing uevent /sys/class/rc/rc0/input17/event9/uevent
/sys/class/rc/rc0/input17/event9/uevent uevent MAJOR=13
/sys/class/rc/rc0/input17/event9/uevent uevent MINOR=73
/sys/class/rc/rc0/input17/event9/uevent uevent DEVNAME=input/event9
Parsing uevent /sys/class/rc/rc0/uevent
/sys/class/rc/rc0/uevent uevent NAME=rc-rc6-mce
/sys/class/rc/rc0/uevent uevent DRV_NAME=ite-cir
/sys/class/rc/rc0/uevent uevent DEV_NAME=ITE8708 CIR transceiver
input device is /dev/input/event9
/sys/class/rc/rc0/protocols protocol rc-5 (disabled)
/sys/class/rc/rc0/protocols protocol nec (enabled)
/sys/class/rc/rc0/protocols protocol rc-6 (disabled)
/sys/class/rc/rc0/protocols protocol jvc (disabled)
/sys/class/rc/rc0/protocols protocol sony (disabled)
/sys/class/rc/rc0/protocols protocol rc-5-sz (disabled)
/sys/class/rc/rc0/protocols protocol sanyo (disabled)
/sys/class/rc/rc0/protocols protocol sharp (disabled)
/sys/class/rc/rc0/protocols protocol mce_kbd (disabled)
/sys/class/rc/rc0/protocols protocol xmp (disabled)
/sys/class/rc/rc0/protocols protocol imon (disabled)
/sys/class/rc/rc0/protocols protocol lirc (enabled)
Opening /dev/input/event9
Input Protocol version: 0x00010001
Protocols changed to nec
Testing events. Please, press CTRL-C to abort.
21169.480721: lirc protocol(nec): scancode = 0x4012
21169.480738: event type EV_MSC(0x04): scancode = 0x4012
21169.480738: event type EV_KEY(0x01) key_down: KEY_POWER(0x0074)
21169.480738: event type EV_SYN(0x00).
21169.533056: lirc protocol(nec): scancode = 0x4012 repeat
21169.533078: event type EV_MSC(0x04): scancode = 0x4012
21169.533078: event type EV_SYN(0x00).
21169.660143: event type EV_KEY(0x01) key_up: KEY_POWER(0x0074)
21169.660143: event type EV_SYN(0x00).
21171.387732: lirc protocol(nec): scancode = 0x4001
21171.387754: event type EV_MSC(0x04): scancode = 0x4001
21171.387754: event type EV_KEY(0x01) key_down: KEY_1(0x0002)
21171.387754: event type EV_SYN(0x00).

That’s it! Now you should be able to control your desktop environment with the remote control.

If after rebooting the computer the keymapping is back to the original one, you can add a script to /etc/rc.local file to set the mapping when the OS starts:

#!/bin/sh -e
ir-keytable -c -p nec -w /etc/rc_keymaps/united
exit 0

Save the file and make it executable with this command:

$ sudo chmod +x /etc/rc.local
comments powered by Disqus

Get the full path of a File using the Storage facade on Laravel

Introduction

This post is just a reference for the various ways of retrieving the full path of a file using the Storage …