IR Control via LIRC on Raspberry Pi Zero W

Even though many modern home appliances have moved to Bluetooth or WiFi (or in some cases some custom radio-based communication) controls, many of them are still controlled via IR. Having a universal IR control attached to an SBC located somewhere in a room is a very powerful feature for a smart home or even a public area. Turning on, raising volume on a TV with a smartphone? Scheduled AC power-up with a target temperature in a hospital waiting room? No problem! In this article we’re going to build a prototype with RasPi Zero, some IR receiver/transmitter diodes and LIRC to record and replay IR commands for a TV. We’ll make our RasPi turn on the TV at a scheduled time and Isaax will help us deploy and update the code.

What is LIRC

When I first thought of controlling my TV via alternative means, the idea was to use Arduino with IR diodes and a desktop PC / SBC to talk to Arduino. While there is a couple of decent IR libraries for Arduino IDE I felt they were a bit bulky to use. Its hard to detect and map commands and add new remote controls if they have different IR protocols. I mean it’s totally doable, just a little bit hard to manage. LIRC on the other hand, significantly reduces the burden of IR command detection and mapping and since RasPi Zero W is a Linux-based SBC and is very comparable to most Arduino/ESP boards price-wise – I’d say it wins as a universal IR control big time. And to add to this: LIRC has wrappers for most modern languages (Python, Node.js, Go, etc.)!

Hardware Setup

Ok, so here is the list of what we will use for the prototype:
  • a Raspberry Pi Zero W
  • a transmitting IR diode
  • a receiving IR diode (I used TSOP1738)
  • the IR remote control from the device you want to control (mine was a Samsung TV)
  • some regular pins to be soldered to the RasPi for the dupont wires (optional)
  • dupont wires (optional)
Here is the self-explanatory fritzing: We wire IR receiver signal to GPIO17 and IR transmitter to GPIO27. Note: If you want a more robust hardware IR solution, take a look at this nice RasPi HAT:

LIRC Setup

While LIRC installation is no different from a usual Linux app, the configuration is a bit tricky. LIRC moved to systemd and devmapper driver as default recently (since 0.9.4), but all of the guides for LIRC+RasPi out there refer to upstart / hardware.conf config. So you might find yourself lost on how to configure LIRC the devmapper way for RasPi. To tackle this we will switch the driver from devmapper to ‘default’, then just add the usual hardware.conf and configure LIRC the old way. Note: If you do know how to configure LIRC on RasPi with devmapper we would love to see your solution down in the comments. Here is step by step guide for RasPi on Raspbian Stretch: Install LIRC:
$ sudo apt-get update
$ sudo apt-get install lirc
Switch from devmapper to default in your /etc/lirc/lirc_options.conf:
driver = default
device = /dev/lirc0
Create /etc/lirc/hardware.conf file with the following content:
In your /boot/config.txt:
GPIO17 for IR input, GPIO27 for output, remember? Restart LIRC:
sudo systemctl stop lircd.service
sudo systemctl start lircd.service
Check LIRC status:
sudo systemctl status lircd.service
And finally reboot:
sudo reboot


Let’s check if our setup works. Stop LIRC:
sudo systemctl stop lircd.service
Use mode2 command to test IR receiver:
mode2 -d /dev/lirc0
Now grab the remote and press some buttons, you should see something like this: If you see similar output, treat yourself – you are halfway there!

Recording Commands

Now is the time for real LIRC magic – command recording. Make sure LIRC is not running and type this:
irrecord -d /dev/lirc0
Then follow the guide and record some commands from your remote. You will be prompted to press random buttons first to ‘generate dots’, then press a single button as fast as you can, etc – real fun! After you’re done LIRC will generate the remote configuration file with the recorded commands. I ended up with a file the looks like this /etc/lirc/lircd.conf.d/tv.lircd.conf:
begin remote
  name  tv
  bits           16
  eps            30
  aeps          100
  header       4484  4536
  one           529  1710
  zero          529   594
  ptrail        532
  pre_data_bits   16
  pre_data       0xE0E0
  gap          108055
  toggle_bit_mask 0x0
  frequency    38000
      begin codes
          key_power                0x40BF
          key_volumeup             0xE01F
          key_volumedown           0xD02F
      end codes
end remote
Notice that I have three commands recorded here : key_powerkey_volumeup and key_volumedown. Pretty obvious, I guess. LIRC has reserved keywords for command names (you won’t be able to enter custom ones), to list them type:
irrecord --list | less
Lets see if we can send the recorded commands. To power up the TV, type:
irsend send_once tv key_power
If your TV went online, treat yourself once again – you are almost there! If not, here are some tips to troubleshoot:
  • use irsend send_start ... to start repeating the command and look at your transmitting IR diode through a camera. Digital cameras detect IR light and you should see it blinking. By the way, that’s how night vision works: you ‘light up’ the scene with invisible IR light (remember those numerous LEDs around surveillance cameras?) and the camera ‘sees’ the scene clearly.
  • if the transmitter is blinking but TV doesn’t react, make sure there are no obstacles between the diode and the TV receiver and the diode ‘is looking directly’ at it. I used a cheap IR LED and it really needed to be directed straight at the TV. But the original IR transmitter from the TV’s remote worked even through the palm of my hand!
  • if the transmitter doesn’t blink – make sure that all the contacts are soldered/connected properly and GPIO config is correct
Note: Bear in mind that AirCon controls (the ones with LCD displays on them) behave differently from TV-like controls. They send configuration, not commands, so you won’t be able to record them with irrecord. Sending configuration is more advanced but, you can, for example, set target value for temperature and set swing mode with one ‘packet’ (i.e. set temperature to 24, swing off). And as you already may have guessed, you can’t set target volume with a TV remote command – only increase/decrease. Detecting and replaying AC configs is a different story and is out of scope of this article, but its is still possible with LIRC.

Wrapping It Up

Now why don’t we control LIRC from our application? I guess there is no reason why we couldn’t call a command and handle its output with any programming language we like. But LIRC has been around for a while and is now quite mature, so mature in fact that convenience wrappers have emerged in many languages. Some languages even have multiple wrappers, some have LIRC/HTTP wrappers, and there is a wrapper for Node-RED too! As I’m a Node.js guy – I’ll demonstrate it using lirc_node npm package. The code is pretty trivial: the TV is powered up on scheduled time each day. I won’t go into detail, you can look at the code here: One small thing to note is, I set the hour and minute for the schedule with env vars. This is done to easily change them via Isaax envars – no code commits needed.

Isaax Setup

If you have no idea how to setup a new project and register a device on Isaax – you are welcome to go through the guides here: User Manual. Before we register our RasPi as an Isaax device, we need to do two things:
  • set up project’s envars for the schedule:
  • change the project’s post-update script so Isaax Agent will install npm packages after each update (but before the apllication actually starts running):
Ok, we are ready to register our RasPi and launch it as an Isaax project’s device. If everything went well, you should see the output in the Isaax ‘Notifications’ pane. In my case, when I update the schedule via envars I see: And when the time comes and the IR command is sent I see: That’s it! You are now prepared for the ultimate IR control hub deployment! Manipulate TVs, heaters, AC units, colored lamps and what not with you RasPi and LIRC… and Isaax. Illustration by Victorgrigas]]>