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.)!
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
- dupont wires (optional)
Here is the self-explanatory fritzing:
We wire IR receiver signal to
GPIO17 and IR transmitter to
Note: If you want a more robust hardware IR solution, take a look at this nice RasPi HAT: https://www.crowdsupply.com/anavi-technology/infrared-phat
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:
$ sudo apt-get update $ sudo apt-get install lirc
default in your
driver = default device = /dev/lirc0
/etc/lirc/hardware.conf file with the following content:
LIRCD_ARGS="--uinput" LOAD_MODULES=true DRIVER="default" DEVICE="/dev/lirc0" MODULES="lirc_rpi" LIRCD_CONF="" LIRCMD_CONF=""
GPIO17 for IR input,
GPIO27 for output, remember?
sudo systemctl stop lircd.service sudo systemctl start lircd.service
Check LIRC status:
sudo systemctl status lircd.service
And finally reboot:
Let’s check if our setup works. Stop LIRC:
sudo systemctl stop lircd.service
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!
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
begin remote name tv bits 16 flags SPACE_ENC|CONST_LENGTH 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_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:
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: https://github.com/yentsun/node-lirc-isaax-example
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.
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