Control Raspberry Pi GPIO With Amazon Echo and Python

137,037

180

89

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 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
First Time Authors Contest 2016

Participated in the
First Time Authors Contest 2016

IoT Builders Contest

Participated in the
IoT Builders Contest

7 People Made This Project!

Recommendations

  • For the Home Contest

    For the Home Contest
  • Big and Small Contest

    Big and Small Contest
  • Game Design: Student Design Challenge

    Game Design: Student Design Challenge

89 Comments

0
Opilite
Opilite

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

0
tommyb82000
tommyb82000

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?

0
nswilhelm
nswilhelm

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)

0
hyptechdev
hyptechdev

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)

0
kubmeister
kubmeister

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.

0
manojraspberry
manojraspberry

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

0
weredouglas
weredouglas

Reply 5 years ago

This really really sorted me out thanks

0
DavidSchh
DavidSchh

Reply 5 years ago

thanks man. that worked for me

0
DanC324
DanC324

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.

0
Ajaxjones
Ajaxjones

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

0
BenjaminF10
BenjaminF10

Reply 5 years ago

Excellent, thanks!

0
dvelazquez
dvelazquez

Reply 6 years ago

This helped me get it running.

Thanks

0
jllwton
jllwton

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?

0
utkarshdixit0612
utkarshdixit0612

Reply 3 years ago

Hi, did you find a solution to this problem? I'm stuck on the same problem.

0
jllwton
jllwton

Reply 3 years ago

No, I did

0
jllwton
jllwton

Reply 3 years ago

No, I didn’t.

0
utkarshdixit0612
utkarshdixit0612

Reply 3 years ago

Did you use any other method for this project or did you drop it?

0
hekami
hekami

Question 4 years ago

Hi,

I am running ngrok and getting this error.

please help me out.

Capture.PNG
0
utkarshdixit0612
utkarshdixit0612

Answer 3 years ago

Hi,
Did you get the solution to this problem? I am also stuck on the same problem.

0
VijayakumarP2
VijayakumarP2

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.