Make any TV voice controlled through Amazon Alexa and Raspberry Pi
If you’re like me and sometimes can’t find your TV remote, you wish you could ask your Echo to turn the TV off, on, change the input source, or increase the volume. Unfortunately, most TVs don’t ship with a packaged Alexa Skill to do such things; on top of that, most TVs don’t have an API endpoint to hit to control such functions to more easily build a custom Skill around. So, I took the long road to make my TV voice controlled: build an internet connected TV remote using a Raspberry Pi and create an Alexa Skill to communicate with it. The good news is that this approach will work with any TV — smart TV, old TV, new TV, dumb TV.
In this tutorial, we’ll create an Alexa Skill and accompanying Raspberry Pi hardware and software that will turn the TV on and off. This tutorial assumes a basic understanding of Raspberry Pi, Alexa Skills, and Python. Once you complete it, you can take your setup a step further and experiment, adding more functionality such as changing channels, sources, and the volume. For a working sample that features these, see this Github repo.
How this will all work in the end
- User says, “Alexa, ask the TV to update.”
- Alexa responds, “How should the TV update?”
- User responds, “Turn the TV on.”
- Alexa responds, “Turning the TV on.”
- Raspberry Pi receives command to blink IR LED for corresponding action resulting in TV turning on.
Components
This tutorial assumes you have the following hardware, software installed on your Raspberry Pi, and accounts:
Hardware
- 1 Alexa device (e.g. Echo)
- 1 Raspberry Pi with internet connection
- 1 IR LED
- 1 IR receiver
- 1 PN2222 transistor
- 1 220 Ω resistor
Software
Accounts
Raspberry Pi wiring
- Pin 22 goes to the transistor
- Pin 23 goes to the IR receiver
LIRC configuration
“LIRC is a package that allows you to decode and send infra-red signals of many (but not all) commonly used remote controls.”, as per their official website.
Configure LIRC for Raspberry Pi
On your Raspberry Pi, run the following to install LIRC:
sudo apt-get install lirc
Add LIRC to your /etc/modules file by running the command below and adding the following:
sudo /etc/modules## /etc/modules
lirc_dev
lirc_rpi gpio_in_pin=23 gpio_out_pin=22
Change your /etc/lirc/hardware.conf file by running the command below and adding the following:
sudo nano /etc/lirc/hardware.conf## /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS="--uinput"
# Don't start lircmd even if there seems to be a good config file
# START_LIRCMD=false
# Don't start irexec, even if a good config file seems to exist.
# START_IREXEC=false
# Try to load appropriate kernel modules
LOAD_MODULES=true
# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"
# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""
Change your /boot/config.txt file by running the command below and adding the following:
sudo nano /boot/config.txt## /boot/config.txt
dtoverlay=lirc-rpi,gpio_in_pin=23,gpio_out_pin=22
Now, restart LIRC so it picks up these changes:
sudo /etc/init.d/lirc stop
sudo /etc/init.d/lirc start
Configure LIRC for your particular remote
This step will configure LIRC to blink the IR LED in the correct cadence, mimicking commands given by your remote control. This step takes a bit of time and involves a lot pointing and clicking at the IR receiver. Just follow the instructions LIRC gives in the terminal.
# Stop LIRC
sudo /etc/init.d/lirc stop
# Create new recording in config file ~/lircd.conf
# This will take your through a series of steps to follow
# Make sure you add the power button and name it 'KEY_POWER'
irrecord -d /dev/lirc0 ~/lircd.conf
# Move the created config file to the folder where LIRC looks for the config files
sudo cp ~/lircd.conf /etc/lirc/lircd.conf
# Start LIRC
sudo /etc/init.d/lirc start
Raspberry Pi files
Our main file, index.py, will control our Alexa Skill and tell LIRC to blink the LED for a given command (which will be ‘KEY_POWER’).
index.py
## index.pyimport osimport json
from pprint import pprintfrom flask import Flask
from flask_ask import Ask, statement, question, sessionapp = Flask(__name__)
ask = Ask(app, '/')lirc_file_conf = '~/lircd.conf'
power_button_command = 'KEY_POWER'@ask.launch
def start_skill():
welcome_message = 'How should the t.v. update?'
return question(welcome_message)@ask.intent('ChangePowerIntent')
def change_power(power_value):
# Tell LIRC to send IR LED blink pattern to turn TV on/off
os.system('irsend SEND_ONCE {} {}'.format(lirc_file_conf, power_button_command)) text = 'Turning the t.v. {}'.format(power_value)
return statement(text)if __name__ == '__main__':
app.run(debug=True)
Run the file by running the following from your terminal:
sudo python index.py
ngrok
Head over to where you have ngrok on your Raspberry Pi and run the following command to open up a local tunnel to your index.py file
./ngrok http 5000
Copy the URL it created (we’ll use this in the next step when we tell our Alexa where to find its Skill through HTTPS).
Amazon Alexa Skill Dashboard
Head over to the Amazon Developer Dashboard and sign in. Under Alexa, click on the ‘Alexa Skills Kit’ and click ‘Get Started >’.
Click ‘Add a New Skill’ on the top right corner’.
In the ‘Skills Information’ tab, the field to pay attention to is ‘Invocation Name’. This is the phrase a user will say to begin the Skill. Make it this:
the t.v. to update
This way, you will say to Alexa, “Alexa, ask the TV to update.”
In the ‘Interaction Model’ tab, in the ‘Intent Schema’ add the following so Alexa knows what function in the index.py file corresponds to what action and what values you can tell it (which is programmed in the next step):
{
"intents": [
{
"slots": [
{
"name": "power_value",
"type": "LIST_OF_POWERS"
}
],
"intent": "ChangePowerIntent"
}
]
}
Create a custom slot in ‘Custom Slot Types’, name it LIST_OF_POWERS, and add the following to it:
on
off
This way, Alexa knows you can only tell it “on” or “off”.
In ‘Sample Utterances’, add the following so Alexa knows what command to respond to:
ChangePowerIntent turn the t.v. {power_value}
In the ‘Configuration’ Tab, change the endpoint to ‘HTTPS’ and add the ‘Default’ URL that was spit out by ngrok followed by a backslash.
This is basically telling Alexa to look at the https://aa87e7e5.ngrok.io/ endpoint for all the information for its Skill.
Save everything.
Try it out!
If all went according to plan, ask Alexa, “Alexa, ask the TV to update.” She will respond with “How should the TV update?” You’ll say, “Turn the TV on.” Your TV should then satisfyingly turn on.
Departing notes
To add more functionalities — like turning the volume up, down, changing channels, changing sources, muting — play around with what series of commands LIRC must perform to accomplish that particular action. This may include navigating through menus, pushing an “Ok” button, etc. Use Python’s ‘time’ library for pausing in between “key” pushes.
Source code
For the fully complete source code (with more functionality) of this project, see this Github repo.