Introduction: Control Raspberry Pi GPIO With Amazon Echo and Python
The main goal of this instructable to use Alexa's voice commands with an Amazon Echo to control the GPIO on a Raspberry Pi using Python. This instructable has been adapted from the Memory Game example at Flask-Ask: A New Python Framework for Rapid Alexa Skills Kit Development.
An Echo is not required but is highly recommended. This is a very simple example but demonstrates how easy it is to expose the Raspberry Pi's functionality to Alexa with just a few lines of Python.
The main reason I am writing this is because I could not find a similar guide elsewhere and felt the functionality was cool enough that it deserved one. There are currently several different ways of adding custom Smart Home programming to Alexa but as far as I know this is the first method using Raspberry Pi and Python.
Step 1: Initial Setup
I used a Raspberry Pi 3 and a fresh Raspbian Jessie-lite image downloaded from https://www.raspberrypi.org/downloads/raspbian/
Two terminal sessions will be needed so using SSH to access the Pi is recommended. Once logged in, enter the following commands to install the required packages and python libraries:
sudo apt-get update && sudo apt-get upgrade -y sudo apt-get install python2.7-dev python-dev python-pip sudo pip install Flask flask-ask
Step 2: Setup Ngrok
I couldn't think of a better explanation so here is a quote from Amazon's guide I linked earlier:
ngrok is a command-line program that opens a secure tunnel to localhost and exposes that tunnel behind an HTTPS endpoint. ngrok makes it so Alexa can talk to your code right away. Follow the next three steps to generate a public HTTPS endpoint to 127.0.0.1:5000.
Visit https://ngrok.com/download and get the latest Linux ARM release as a zip and unzip inside the home directory:
unzip /home/pi/ngrok-stable-linux-arm.zip
Next, run it from the command line with:
sudo ./ngrok http 5000
Your screen should look like the image above. Note the 'Forwarding' URL that starts with https, it will be used later.
Note: Unfortunately the ngrok URL changes every time the service is started so it is not a permanent solution if you are trying to run this full time. I'd recommend a service like Yaler or Page Kite if you need a more permanent URL to use with your new Skill.
Step 3: Python Script
Open a new terminal session and create a new python file named gpio_control.py:
nano gpio_control.py
Copy/paste the following code into the new file:
from flask import Flask
from flask_ask import Ask, statement, convert_errors import RPi.GPIO as GPIO import loggingGPIO.setmode(GPIO.BCM)
app = Flask(__name__) ask = Ask(app, '/')
logging.getLogger("flask_ask").setLevel(logging.DEBUG)
@ask.intent('GPIOControlIntent', mapping={'status': 'status', 'pin': 'pin'}) def gpio_control(status, pin):
try: pinNum = int(pin) except Exception as e: return statement('Pin number not valid.')
GPIO.setup(pinNum, GPIO.OUT)
if status in ['on', 'high']: GPIO.output(pinNum, GPIO.HIGH) if status in ['off', 'low']: GPIO.output(pinNum, GPIO.LOW)
return statement('Turning pin {} {}'.format(pin, status))
Save and close the file.
Start the flask server with:
sudo python gpio_control.py
Leave both ngrok and gpio_control.py running while we setup the new skill in AWS...
Step 4: AWS Account
First create or login to your AWS Developer Account and open your list of Alexa skills.
Step 5: Alexa Skill - Information
Set the Skill Name to 'GPIO Control' and the Invocation Name to the word(s) you want to use to activate the skill. Click 'Next' to continue.
Step 6: Alexa Skill - Interaction Model
Copy/paste the following into the 'Intent Schema' box:
{
"intents": [{"intent": "GPIOControlIntent",
"slots": [{
"name": "status",
"type": "GPIO_CONTROL"
}, {
"name": "pin",
"type": "AMAZON.NUMBER"
}]
}]
}
Next, click 'Add Slot Type' and under 'Enter Type' write in 'GPIO_CONTROL'. Under 'Enter Values' write:
on off
This is just a simple example. 'high', 'low' or pretty much any other word could be added.
Copy/paste the following into the 'Sample Utterances' box:
GPIOControlIntent to turn pin {pin} {status}
Click on 'Save' and then 'Next'.
Step 7: Alexa Skill - Configuration
Select 'HTTPS' as the Service Endpoint Type and select a region.
Enter the ngrok URL from step 2 and click 'Next'. The URL should be something like:
https://ed6ea04d.ngrok.io
Step 8: Alexa Skill - SSL Certificate
Select the 'My development endpoint is a sub-domain of a domain that has a wildcard certificate from a certificate authority' option and click 'Next'.
Step 9: Alexa Skill - Testing
If everything was setup correctly you should now see a screen similar to the first image above. The Skill is now enabled and can be accessed through any Amazon Echo device(or at http://echosim.io/) that is connected to your AWS Developer Account using the following syntax:
Alexa, tell Raspberry Pi to turn pin {pin number} {on or off}
For example:
Alexa, tell Raspberry Pi to turn pin twenty one on
If you are having any issues, the simplest way to test the Skill would be to use the Voice or Service Simulator found on the Test page. Try entering the following into the 'Enter Utterance' box under the Service Simulator:
turn pin twenty one on
Then hit 'Ask GPIO Control' to run the test.
Step 10: Wrapping Up
After testing there is no need to continue through the Skill setup any further as the rest applies to releasing the skill publicly. As far as I can tell there is nothing stopping someone from running this continuously in a 'development' mode for personal use though... My ultimate goal is to use this to integrate Alexa into my existing Raspberry Pi-based Smart Home setup so that everything can be controlled hands-free.
This was my first Instructable so any feedback is appreciated. If you have any questions or trouble setting this up I will do my best to help. Good luck!
Step 11: Bonus Points - Using Words Instead of Pin Number
If you've followed all of the above steps and want to add some more functionality you can create an intent that can be called with actual words like 'fan' or 'light' by following the steps below.
Add the following code to gpio_control.py:
@ask.intent('LocationControlIntent', mapping={'status': 'status', 'location': 'location'})
def location_control(status, location):locationDict = { 'fan': 12, 'light': 21 }
targetPin = locationDict[location]
GPIO.setup(targetPin, GPIO.OUT)
if status in ['on', 'high']: GPIO.output(targetPin, GPIO.HIGH) if status in ['off', 'low']: GPIO.output(targetPin, GPIO.LOW)
return statement('Turning {} {}!'.format(location, status))
Copy/paste the following into the 'Intent Schema' box:
{ "intents": [{ "intent": "LocationControlIntent", "slots": [{ "name": "status", "type": "GPIO_CONTROL" }, { "name": "location", "type": "LOCATION" }] }] }
Next, click 'Add Slot Type' and under 'Enter Type' write in 'LOCATION'. Under 'Enter Values' write down any words you want to be able to use to trigger this intent, for example:
fan light television
Copy/paste the following into the 'Sample Utterances' box:
LocationControlIntent to turn {location} {status} LocationControlIntent to change the {location} to {status}
Click on 'Save' and it will update your settings and after that the new phrases will be usable. Example:
Alexa, tell Raspberry Pi to turn fan on Alexa, tell Raspberry Pi to change the light to off

Participated in the
First Time Authors Contest 2016

Participated in the
IoT Builders Contest
7 People Made This Project!
- AD PVT LTD made it!
- VijayakumarP2 made it!
- NimeshG2 made it!
- David_Lin made it!
See 3 More
89 Comments
7 months ago
can't run gpio_control.py . gives error: Traceback (most recent call last):
File "/home/admin/gpio_control.py", line 2, in
from flask_ask import Ask, statement, convert_errors
File "/usr/local/lib/python3.9/dist-packages/flask_ask/__init__.py", line 9, in
from .core import (
File "/usr/local/lib/python3.9/dist-packages/flask_ask/core.py", line 10, in
from werkzeug.contrib.cache import SimpleCache
ModuleNotFoundError: No module named 'werkzeug.contrib'
"werkzeug" is from german and means 'tool'
PS: the command to start ngrok isn't (anymore) sudo ./ngrok ... but just sudo ngrok
UPDATE: I've just readen the comments below, and i have got rid of that error, but now i hav another : File "/home/admin/gpio_control.py", line 16
try:
^
IndentationError: expected an indented block
Question 2 years ago on Step 9
Hello, when I go to test the skill within the Amazon developer page, I get a 500 INTERNAL SERVER ERROR message on ngrok and the pin doesn't appear to be toggling as expected. Any ideas?
6 years ago
I'm new to python and Pi...and Linux so I might have missed something but for me to get this to work I had to add this code to the end of gpio_control.py
if __name__ == '__main__':
port = 5000 #the custom port you want
app.run(host='0.0.0.0', port=port)
Reply 5 years ago
thank you, I have to add your code to work:
from flask import Flask
from flask_ask import Ask, statement, convert_errors
import RPi.GPIO as GPIO
import logging
GPIO.setmode(GPIO.BCM)
app = Flask(__name__)
ask = Ask(app, '/')
logging.getLogger("flask_ask").setLevel(logging.DEBUG)
@ask.intent('GPIOControlIntent', mapping={'status': 'status', 'pin': 'pin'})
def gpio_control(status, pin):
try:
pinNum = int(pin)
except Exception as e:
return statement('Pin number not valid.')
GPIO.setup(pinNum, GPIO.OUT)
if pinNum == 5 or pinNum == 6 or pinNum == 26 or pinNum == 27:
if status in ['on', 'high']: GPIO.output(pinNum, GPIO.LOW) #reversed pins on relay
if status in ['off', 'low']: GPIO.output(pinNum, GPIO.HIGH)
else:
if status in ['on', 'high']: GPIO.output(pinNum, GPIO.HIGH)
if status in ['off', 'low']: GPIO.output(pinNum, GPIO.LOW)
return statement('Turning pin {} {}'.format(pin, status))
if __name__ == '__main__':
port = 5000 #the custom port you want, 5000 must be open/or port forward from the router
app.run(host='0.0.0.0', port=port)
Reply 3 years ago
confused … I copied this whole thing and it didn't work. Fails for me
sudo python alexa_gpio_control.py
File "alexa_gpio_control.py", line 16
try:
^
To be honest, does anyone want to create an updated version of this article to reflect the new Alexa Developer Console page? it is nothing like this article these days.
Here is what I am trying to do. My Pi has three GPIO pins connected to relay switches on Pin 37, 38 and 40. I want to be able to say "Alexa, tell Raspberry Pi to open switch 1" or "Alexa, tell Raspberry Pi to close switch 1" where switch 1 is mapped to pin 37.
Reply 5 years ago
Hi,
Thanks for such a wonderful and simple method. It really worked. But I have one question, When I say turn fan on , actually it turns off and Vice Versa...Hope there is something wrong in my relay or ??
Thanks,
Manoj
Reply 5 years ago
This really really sorted me out thanks
Reply 5 years ago
thanks man. that worked for me
Reply 4 years ago
Great! That was really helpful. With that I got it to work. However, not at first becuase I did not pay attention to indenting in the right place, and had put this code snippet within the def gpio_control.
Reply 5 years ago
this did the trick to get the gpio_control.py working.
I also had to run through some hoops to get flask up and running.
sudo apt-get install build-essential libssl-dev libffi-devython-dev
and also had to sudo pip install flask_ask as well
Reply 5 years ago
Excellent, thanks!
Reply 6 years ago
This helped me get it running.
Thanks
5 years ago
I'm getting a "405 method not allowed" error from ngrok when Amazon attempts to connect to the Echo. At first I thought it was an issue with port forwarding on my router (BT Smart Hub), so I tried connecting via the Pi's own browser to http://localhost:5000/ but that too returns the same error. Has anyone encountered and solved this issue, please?
Reply 3 years ago
Hi, did you find a solution to this problem? I'm stuck on the same problem.
Reply 3 years ago
No, I did
Reply 3 years ago
No, I didn’t.
Reply 3 years ago
Did you use any other method for this project or did you drop it?
Question 4 years ago
Hi,
I am running ngrok and getting this error.
please help me out.
Answer 3 years ago
Hi,
Did you get the solution to this problem? I am also stuck on the same problem.
5 years ago
Hi, on raspberry pi ngrok is running on 4040, so I started ngrok with sudo ./ngrok http 4040. http://localhost:4040 is taking to default site. However when I test from Alexa service simulator, i am keep getting 405 method not allowed error ( expecting GET, but receiving POST) . I tried port forwarding on router for tcp/udp 443 to 4040. but no luck. anyone facing the same issue and able to resolve? please help.