loading

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 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 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
<p>Thanks Patrick</p><p>I was able to turn on/off LED connect to raspberry pi with Alexa.</p><p>Could you/anyone help in for how to change the pin with device name.</p><p>i.e. how to change the command </p><p>from </p><p>Alexa, tell Raspberry Pi to turn pin twenty one on</p><p>to </p><p>Alexa, tell Raspberry Pi to turn &quot;FAN&quot; on</p><p>In service request i'm getting:</p><p>&quot;name&quot;: &quot;GPIOControlIntent&quot;,<br> &quot;slots&quot;: {<br> &quot;pin&quot;: {<br> &quot;name&quot;: &quot;pin&quot;,<br> &quot;value&quot;: &quot;?&quot;</p>
<p>Hi, I also want this type of command. Did you find out how to do it ?</p><p>Thanks</p>
<p>I updated the guide. Please see step 11.</p>
<p>Thanks but I am missing something. Please bare with me:</p><p>1. I added the code to the end of gpio_control.py. I did not delete the former code</p><p>2. I deleted the former Intent Schema Box because it was giving me Save errors</p><p>3. I created the slot types but did not delete the previous one</p><p>4. I created the 2 new Utterances and deleted the previous one</p><p>Now, in test it seems to work (turn fan on) but, and here is my question, how do I map FAN to GPIO pin 25 ?</p><p>Thanks for your help. Wonderful job.</p><p>Regards</p>
<p>I updated the code for the LocationControlIntent. That should get it working with a fan and can be customized based on the location/pin combination you are interested in.</p>
<p>Patrick, It's working great. I am controlling now 6 GPIO pins (Up, Down, Stop - Left and Right blinds).</p><p>Next step will be to replace ngrok to a permanent solution and launch </p><p>gpio_control.py program automatically so as to enable everything when booting.</p><p>Again, thanks for your help</p>
<p>Hi, it's working great, thanks. Tomorrow I will change the word in order to move my blinds up &amp; down with voice commands.</p><p>Thanks for you help.</p>
<p>I got the following errors when i run the gpio_control.py<br><br>Traceback (most recent call last):</p><p> File &quot;gpio_control.py&quot;, line 2, in &lt;module&gt;</p><p> from flask_ask import Ask, statement, convert_errors</p><p> File &quot;/usr/local/lib/python2.7/dist-packages/flask_ask/__init__.py&quot;, line 9, in &lt;module&gt;</p><p> from .core import (</p><p> File &quot;/usr/local/lib/python2.7/dist-packages/flask_ask/core.py&quot;, line 12, in &lt;module&gt;</p><p> from . import verifier, logger</p><p> File &quot;/usr/local/lib/python2.7/dist-packages/flask_ask/verifier.py&quot;, line 8, in &lt;module&gt;</p><p> from OpenSSL import crypto</p><p> File &quot;/usr/local/lib/python2.7/dist-packages/OpenSSL/__init__.py&quot;, line 8, in &lt;module&gt;</p><p> from OpenSSL import rand, crypto, SSL</p><p> File &quot;/usr/local/lib/python2.7/dist-packages/OpenSSL/rand.py&quot;, line 12, in &lt;module&gt;</p><p> from OpenSSL._util import (</p><p> File &quot;/usr/local/lib/python2.7/dist-packages/OpenSSL/_util.py&quot;, line 6, in &lt;module&gt;</p><p> from cryptography.hazmat.bindings.openssl.binding import Binding</p><p>ImportError: No module named cryptography.hazmat.bindings.openssl.binding</p>
<p>Try</p><p>pip install cryptography </p><p>this will solve your problem.<br></p>
<p>This works for me..</p><p>Thank you..</p>
<p>Very nicely explained. Worked for me perfectly. Only that I had to install couple of dependencies separately. Also instruction model in amazon developer account doesn't let you do all the things the way they are mentioned here. But still doable, thank you so much for this. </p>
<p>Traceback (most recent call last):</p><p>File &quot;gpio_control.py&quot;, line 2, in &lt;module&gt;</p><p>from flask_ask import Ask, statement, convert_errors</p><p>ImportError: No module named 'flask_ask'</p><p>I have installed flask ask but still it showing this error.</p><p>Can u help ??</p>
<p>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</p><p>if __name__ == '__main__':</p><p>port = 5000 #the custom port you want</p><p>app.run(host='0.0.0.0', port=port)</p>
<p>thank you, I have to add your code to work:</p><p>from flask import Flask<br>from flask_ask import Ask, statement, convert_errors<br>import RPi.GPIO as GPIO<br>import logging<br><br>GPIO.setmode(GPIO.BCM)<br><br>app = Flask(__name__)<br>ask = Ask(app, '/')<br><br>logging.getLogger(&quot;flask_ask&quot;).setLevel(logging.DEBUG)<br><br>@ask.intent('GPIOControlIntent', mapping={'status': 'status', 'pin': 'pin'})<br>def gpio_control(status, pin):<br><br> try:<br> pinNum = int(pin)<br> except Exception as e:<br> return statement('Pin number not valid.')<br><br> GPIO.setup(pinNum, GPIO.OUT)<br> <br> if pinNum == 5 or pinNum == 6 or pinNum == 26 or pinNum == 27:<br> if status in ['on', 'high']: GPIO.output(pinNum, GPIO.LOW) #reversed pins on relay<br> if status in ['off', 'low']: GPIO.output(pinNum, GPIO.HIGH)<br> else:<br> if status in ['on', 'high']: GPIO.output(pinNum, GPIO.HIGH)<br> if status in ['off', 'low']: GPIO.output(pinNum, GPIO.LOW)<br><br> return statement('Turning pin {} {}'.format(pin, status))<br><br>if __name__ == '__main__':<br> port = 5000 #the custom port you want, 5000 must be open/or port forward from the router</p><p> app.run(host='0.0.0.0', port=port)</p>
<p>This helped me get it running.</p><p>Thanks</p>
<p>I'm getting a &quot;405 method not allowed&quot; 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?</p>
<p>I have a very strange situation. Simulator works fine but when I tell Alexa the command, it gives a sound of acknowledge and does nothing. It seems that it understood the command but failed to execute it.</p><p>But if I use the REVERB app, either for iOS or Android, it works fine. It seems Alexa is not capable to forward the commands but RVEREB is. Any ideas ?</p><p>Thank you</p>
<p>I just found out that changing Alexa's language from UK English to US English solved the situation. Now it works perfectly.</p>
Test OK! Great!
<p>So my command &quot;turn pin twenty one on&quot; is working in Service Simulator, it turn on the pin on and off, all good. It also appears Enabled in the Amazon Alexa app under Your Skills (for some reason you cant see developed skills through the browser). But it seems Alexa does not understand my command so when i say &quot;Alexa, tell Raspberry Pi to turn pin twenty one on&quot; (Invocation Name is Raspberry Pie just like in the guide) either she answers &quot;i dont understand&quot; or &quot;i cant see a device named Raspberry Pi&quot;. Anyone experiencing something similar?</p>
<p>ditto here logicron. test works great, skill shows up on my iphone and alexa says &quot;can't find that...&quot;</p>
<p>I am experiencing this. Did you solve it ? Can you please tell me how ?</p><p>Thank you and regards</p>
<p>Great instructable ! Was able to do in 30 mins &lt;.<br>Some explanation on the python code would be great. For example where is the gpio_control function call ?<br>How the intent schema works ?</p>
<p>OK, thanks for offering help.</p><p>So my command &quot;turn pin twenty five on&quot; is working in Service Simulator, it turns the pin on and off, all good. It also appears Enabled in the Amazon Alexa app under Your Skills with the correct invocation name. But it seems Alexa does not understand my command so when I say &quot;Alexa, tell Butler to turn pin twenty five on&quot; (Invocation Name is Butler) either she answers &quot;I dont understand&quot; or &quot;I cant see a device named Raspberry Pi&quot; or a beep but no action. I am not getting any verbal response from Alexa something like &quot;Turning pin 25 off&quot; either.</p><p>Thank you</p>
<p>Can somebody help me understand the code</p>
<p>Thank you for a great Instructable! Im getting an error when i use the Service Simulator to turn pin twenty one on. I get error message in the Service Responce &quot;There was an error calling the remote endpoint, which returned HTTP 502 : Bad Gateway&quot;. Can anyone help me please</p>
<p>yeah, i had that too. just add this code after the &quot;return statement...&quot;</p><p>if __name__ == '__main__':</p><p>port = 5000 #the custom port you want</p><p>app.run(host='0.0.0.0', port=port)</p><p>....also make sure ngrok then uses that same port number</p>
<p>Thanks. This helped a lot.</p>
<p>It works for me now with the Service Simulator, but i cant get Alexa to understand the command when i ask her myself. Did you also experience that?</p>
<p>Thank you that worked! </p>
<p>I get the same error.</p><p>Should gpio_control.py keep running? it closes after I call it with sudo python gpio_control.py....</p>
<p>Yes it seems you need to run both gpio_control.py and ngrok. Works for me now after <a href="https://www.instructables.com/member/nswilhelm" rel="nofollow">nswilhelm</a> told me to add the code below.</p><p>if __name__ == '__main__':</p><p>port = 5000 #the custom port you want</p><p>app.run(host='0.0.0.0', port=port)</p>
<p>It took a while but I made it work, congratulations</p>
<p>First of all thank you for the nice example. Test section successfully completed. But it did not work when it came to command by voice.</p><p>Alexa, tell Raspberry Pi to turn pin twenty one on <br>If I type the command in the test box. Not working with sound</p>
<p>Great tutorial!</p><p>I also added nswilhelm's code to ngrok. Thanks :-)</p><p>For a couple of hours it didn't work properly, but then I carefully (!!) re-read the instructions and caught that I hadn't been using the correct syntax. Here it is:</p><p>Alexa, tell Raspberry Pi to turn pin {pin number} {on or off}</p><p>Here's a pic of my setup with Pi-Top, and photo board.</p><p>Regards,</p><p>Stuart</p>
<p>There is way to create your own certificate if you have a dns forward IP. I do have a dyndns,org account and it is working great. Just follow the method display by amazon. <a href="https://developer.amazon.com/appsandservices/solutions/alexa/alexa-skills-kit/docs/testing-an-alexa-skill#create-a-private-key-and-self-signed-certificate-for-testing" rel="nofollow">Learn how to create a self signed certificate.</a></p><p>Add the ssl_context into your python script et voila! no need to ngrok.</p><p>if __name__ == '__main__':</p><p>app.run(host='192.168.1.22',port=5000,debug=True,ssl_context=('certificate.pem','private-key.pem'))</p><p>My router forward the port 5000 to my raspberry Pi IP which is 192.168.1.22</p>
<p>I tried this but it's not working :-( </p><p>If I config skill to connect to my dns-adress, the request does not even come trough to flask-server. If I try URL in webbrowser I get &quot;405 Method not allowed&quot; what would be correct.</p><p>At the end if I use curl on my rpi to call flask-server it is reached but I got &quot;ValueError: No JSON object could be decoded&quot;. so what is wrong?</p>
<p>additional info: I use fritz!box 6360 cable in germany as router. using </p><p>myfritz.net dns-service</p>
<p>The router forward the port 5000 to the Pi but outside it is the https port which is 443.</p><p>InternetIP port 443 to intranet IP port 5000</p>
<p>actually on port 443 webinterface of fritz!box is already running! so I suggested is is outside 5000 to inside 5000</p>
<p>Getting 502 bad gateway on step 9.</p><p>My ngrok window is also saying in red text 502 Bad Gateway</p>
<p>Anyone knows of a free service altenate to ngrok, simplified https tunneling without having to mess around with your router?</p>
<p>This is working great for me (sort of). I went ahead and used a paid ngrok account to keep a fixed subdomain name. Everything works fine as long as I use the Alexa unit. However if I use Alexa on my Kindle Fire, I get an error on the Kindle Fire that says &quot;The skill responded with 500 HTTP status code&quot; Ngrok gives me a &quot;500 internal server error&quot; and the python script says &quot;an exception occurred while dispatching the request to the skill&quot; and &quot;Type: Invalid response&quot;. I'm really new to all of this, so I have no idea where to even start. I am able to use the Kindle Fire to control other skills (i.e. Kasa). Anyone have any ideas? </p>
<p>Thanks a lot, this is epic...</p><p>I used to use IFTTT, adafruit IO and MQTT to control my lights...but through your instructable I have eliminated the middle men</p>
<p>This is awesome. Got mine to work. Thanks for the great project. </p>
<p>Excellent project and instruction set. The only delay I had was in getting the skill to become visible. I am in the UK so had to create a UK version of the skill before it was accessible.</p><p>I have a DDNS service. Has anyone posted about using DDNS rather than the ngrok approach? </p>
<p>Page Kite link is *DEAD* !!!</p>
Is cool but the response is still slow, around 10s for one command... <br>https://youtu.be/gc2daxC4B_w
<p>Hey, love your instructable. I use ngrok also, but I hit the endpoints with http calls. That way my skill can interact with multiple end points. Here http://residentsleeper.blogspot.com/2016/12/alexa-severs-and-python.html</p>
<p>This has amazing possibilities - Ask Alexa to run a python script on the RPI which has a temp sensor and return the results - such as the temperature in your office. Or have Alexa inform you that a door monitored by RPI has now opened.</p><p>Excellent Instructable. </p>

About This Instructable

41,701views

134favorites

License:

More by PatrickD126:Control Raspberry Pi GPIO With Amazon Echo and Python 
Add instructable to: