Using infrared control from Amazon Echo

A while back I built a skill adapter to allow Amazon Echo’s smart home skill system to manage my LightwaveRF lights via my custom Octoblu+MQTT system. But why stop there? If I can say “Alexa, turn on the living room light” why can’t I also say “Alexa, turn on the TV“? With IoT mains power sockets such as Belkin Wemo or LightwaveRF I could power on and off the TV but I prefer to leave the TV in standby (yes, I know this uses power and kills the planet). Instead I decided to solve the problem by using infrared emitters glued to the front of the devices I wanted to control and allowing Alexa to control these.

Hardware

ircircuit2Each TV in my house is co-located with a Raspberry Pi running the Kodi media player. Therefore it made sense to add the IR emitter capability to these rather than add more hardware. There are various options for emitting IR including USB IR blasters and professional systems design for commercial AV use-cases. I chose a homebrew route and built my own emitters using an IR LED, a NPN transistor and a couple of resistors. The whole thing connects to a Raspberry Pi GPIO pin. Using a transistor allows for higher LED currents than can be used directly from the GPIO pin and allows multiple emitters to be connected to the same GPIO pin, e.g. to connect several home entertainment devices.

irhead2

I wired the four components together in free space (no board) and connected to a three core cable. I used offcuts of cable sheath and heatshrink tubing to insulate and encapsulate everything. The end result is an IR LED poking out the top of black blob on the end of a black cable. It looks a bit ugly close-up but once attached to a black TV case it’s hardly noticeable.

I connected the other end of the cable to the GPIO header on the Raspberry Pi using +5V, GND and GPIO17 (this is the default for the LIRC Pi GPIO drive) pins. I then positioned and superglued the emitter onto the front of the TV such that it could see the TV’s IR receiver but without completely blocking it.

irtv

Kodi interface

The Raspberry Pi runs the LibreELEC distribution of Kodi. To set this up to use GPIO-driven IR required me to SSH to the Pi as root and edit /flash/config.txt to add a line “dtoverlay=lirc-rpi” – this is needed to load the kernel driver for Raspberry Pi GPIO for the Linux IR subsystem. I then needed to download the specific IR configurations I needed for my devices. For example for my Sony Bravia TV I ran:

 wget -O "/storage/.config/lircd.conf" \
  'https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/sony/RM-ED009.lircd.conf?format=raw'

For controlling multiple devices multiple remote control configs can be concatenated into the lircd.conf file.

After a reboot it was time to code a Kodi add-on. This add-on runs as a service and connects to my home MQTT broker in order to receive published messages (more of which later). The MQTT message handler spawns the “irsend” command (comes with the LibreELEC distribution) to send the named IR command(s). For example, the following code is used to control the TV and an amplifier at the same time (using two IR emitters wired to the same GPIO pin):

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    global player, hdmiattempts, hdmiinput

    try:
        msgpayload = str(msg.payload)
        print(msg.topic+" "+msgpayload)
        ll = msg.topic.split("/")
        if len(ll) > 2:
            if ll[2] == "TV":
                log("Incoming TV command: " + msgpayload)
                ircmds = []
                if msgpayload.lower() == "off":
                    ircmds.append(["Sony_RM-ED009-12", "KEY_POWER", 5])
                    ircmds.append(["Marantz_RMC-73", "Amp_Standby", 1])
                elif msgpayload.lower() == "on":
                    ircmds.append(["Sony_RM-ED009-12", "KEY_POWER", 5])
                    ircmds.append(["Marantz_RMC-73", "Amp_Standby", 1])
                else:
                    ll = msgpayload.split("/")
                    ircmds.append([ll[0],ll[1],1])
                if len(ircmds) > 0:
                    log("Sending IR commands: " + str(ircmds))
                    for ircmd in ircmds:
                        cmd = "/usr/bin/irsend --count %u -d /run/lirc/lircd-lirc0 SEND_ONCE %s %s" % (ircmd[2], ircmd[0], ircmd[1])
                        os.system(cmd)
                        time.sleep(1)
    except Exception, e:
        log("MQTT handler exception: " + str(e))

I developed the add-on in-place on the Raspberry Pi (as opposed to building a distributable package and importing it through Kodi’s UI). To do this I firstly created a directory:

# mkdir /storage/.kodi/addons/service.mqtt.jamesbulpin

Within this I created two files:

And a subdirectory “resources” containing:

Overall the structure was this:

LoungeTV:~/.kodi/addons/service.mqtt.jamesbulpin # find . -type f
./resources/__init__.py
./resources/settings.xml
./resources/language/english/strings.xml
./resources/paho/__init__.py
./resources/paho/mqtt/__init__.py
./resources/paho/mqtt/client.py
./resources/paho/mqtt/subscribe.py
./resources/paho/mqtt/publish.py
./mqttservice.py
./addon.xml

The full code can be found at https://bitbucket.org/jbulpin/kodihomeautomation – note that this includes hard-coded IR devices and commands so would need customisation before use.

kodiconfigThe easiest way to get Kodi to discover the add-on is to reboot. It may also be necessary to enable the add-on via the “My add-ons” menu in Kodi. The settings dialog can also be accessed from here – this allows setting of the MQTT broker IP address and of the name that will be used in the MQTT topic the add-on subscribes to – if this is set to “Lounge” then the topic prefix is “KODI/Lounge“.

With the add-on running I tested it by manually sending MQTT messages:

# mosquitto_pub -m on -t KODI/Lounge/TV

Control with Amazon Echo

So far I’ve described how to get from a MQTT message through to an infrared control action on a TV. The next step was to have the MQTT message be sent in response to an Amazon Echo voice command. Happily this was very easy because I’d already built infrastructure to send MQTT commands (albeit to manage lighting) from Alexa. To add TV control was just a matter of adding another entry to the list of devices returned by the skill adapter when a discovery was initiated, and then initiating a discovery (“Alexa, discover my smart home devices“).

Example of an existing entry:

                {
                    "applianceId":"DiningRoomLights",
                    "manufacturerName":"James Bulpin",
                    "modelName":"LWRF",
                    "version":"v0.1",
                    "friendlyName":"Dining room lights",
                    "friendlyDescription":"Fireplace lights in the dining room",
                    "isReachable":True,
                    "actions":[
                        "turnOn",
                        "turnOff"
                    ],
                    "additionalApplianceDetails":{
                        "mqttTopics":"Light/Dining/Fireplace"
                    }
                },

New entry for the TV:

                {
                    "applianceId":"loungetv",
                    "manufacturerName":"James Bulpin",
                    "modelName":"LWRF",
                    "version":"v0.1",
                    "friendlyName":"TV",
                    "friendlyDescription":"Living room TV and amp",
                    "isReachable":True,
                    "actions":[
                        "turnOn",
                        "turnOff"
                    ],
                    "additionalApplianceDetails":{
                        "mqttTopics":"KODI/Lounge/TV"
                    }
                },

You can see this just uses the KODI MQTT message instead of a lighting message. Alexa has no idea it’s a TV rather than a light that’s being controlled. The entire skill adapter code can be seen here.

Of course it’s also possible to control multiple devices from a single Alexa command, just by sending multiple MQTT messages.

An enhancement

This all works well but you may have noticed that the IR commands to turn the TV on and off are the same – this is because that’s usually how IR remote controls work. This means that any command, via Alexa or otherwise, will actually toggle the current power state rather than move to the defined state. In most cases this isn’t a problem, for example why would you ask Alexa to turn the TV on if it’s on already? However for other more complicated automation activities I’d like to be able to control the TV without knowing whether it’s on or off already (e.g. I want an “all off” button or timer for a bedroom that will turn off all lights and the TV no matter what was already on).

To do this I added an input to sense if the TV was on – power being available on a TV USB port was my chosen method. I used a small opto-isolator, driven by the USB power, with the other side connected to a GPIO input.

To use this in the Kodi add-on I first had to add the “Script – Raspberry Pi Tools” add-on (search the registry from the Kodi add-on manager UI to find this) to add the GPIO Python library. To use this from my add-on code I added:

sys.path.append('/storage/.kodi/addons/virtual.rpi-tools/lib')
import RPi.GPIO as GPIO

# Set up pin for TV power monitoring (active low)
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN)

Then added simple checks in the MQTT message handler to only send IR commands if the current state is not the commanded state:

                if msgpayload.lower() == "off":
                    if GPIO.input(23) == 0:
                        # Only send if the TV is on - (GPIO pin is low)
                        ircmds.append(["Vestel_TV", "OFF", 5])
                elif msgpayload.lower() == "on":
                    if GPIO.input(23) == 1:
                        # Only send if the TV is off - (GPIO pin is high)
                        ircmds.append(["Vestel_TV", "OFF", 5])

In a future blog post I’ll show how I extended this TV control to add automatic input source selection by interfacing to, and automating a HDMI switcher box.

alexatv

Advertisements

1 thought on “Using infrared control from Amazon Echo”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s