Introduction: Home Automation With Amazon Echo Voice Control
Last month, Amazon released the Echo - a small cylinder capable of powerful voice recognition.
The Echo itself is closed source. But once you figure out the Echo's secrets, it becomes an incredibly powerful tool for voice control, enabling you to control anything in your home or apartment via voice without having to worry about the complexities of the human voice. (see: how to do voice control pre-Echo - hint: it's MUCH harder)
In this Instructable, I'll cover how to use the Amazon Echo to control any device via wifi or MQTT.
All you need is:
- An Amazon Echo that's set up with Amazon's instructions
- A Raspberry Pi or other computer running Linux
- The starter code
Difficulty: You'll need to know a little bit of Python programming to understand the examples.
Time required: 10 - 30 minutes from unboxing to Alexa.
Note: This Instructable is currently Linux-only. Let us know if you'd like it on other platforms - if there's enough interest, we'll look into it!
Step 1: Set Up Your Server
With your Echo up and running, let's talk hacking and home automation.
Specifically, we're about to create a server that pretends to be a WeMo device.
The Echo integrates with the WeMo home automation protocol - simply say "Alexa, discover my devices" and it'll search the local network for WeMo devices. So let's give it a device to discover!
1. Install the requirements: Python 2.7, pip and required Python modules
sudo apt-get install python-pip ; sudo pip install requests
2. Download a zip of the code from the GitHub repo
wget "https://github.com/toddmedema/echo/archive/master.zip"
3. Extract the zip file
unzip master.zip -d echo
4. Move to the newly created echo folder
cd echo/echo-master
5. Start the server - you should see some debugging text indicating the server has started polling.
python example-minimal.py
6. Say to your Echo "Alexa: discover my devices". She'll take a few seconds to find the new device. If she doesn't find it the first time, try killing and restarting the process and discovering devices again.
7. Now try it out! Say, "Alexa: turn off device", or "Alexa, device on". You'll see True or False for on/off, along with the Echo's IP address.
Footnote:
The Echo can also send commands via the Amazon cloud, using their new service called Lambda. This is a convenient way to get started with the Echo, but not great for home automation. It requires that every command include the name of the program, ie "Alexa, ask HOME to turn on the lights", and it also involves a network round trip to distant servers, which slows down the response time.
What we really want is to control local devices locally, without the prefix - ie "Alexa, turn on the lights" - which is why I'm using the WeMo protocol.
Step 2: Control EVERYTHING!
That's all there is to it. You now have a server connected to your Amazon Echo. You can now use your voice to:
- Control the lights, air conditioner, even your TV!
- Run scripts on your computer
- Toggle entire home automation modes ("movie mode", "party mode", etc)
- Prank your roommates
- Save power by making it easier to turn off devices you aren't using
We've set up our apartment to run an Echo in each room, controlling all of our home automation devices via the maker-friendly MQTT protocol.
Read on to learn about MQTT and how to use multiple Echos.
Step 3: (bonus) Using MQTT to Control Devices
MQTT makes controlling home automation devices a breeze using a "publisher-subscriber" or "pub-sub" framework. With pub-sub, you publish messages to topics, and any devices listening on those topics receive those messages. So, for example, you could have a topic bedroom-lights and publish "1" or "0" to turn the lights on or off.
Here's how to use the code I wrote to connect the Amazon Echo to MQTT:
- Use pip to install MQTT by opening up a command window and typing:
pip install paho-mqtt
- You can now run the test MQTT file with
python fauxmo_mqtt_example.py
- Open up a web browser and browse to the HiveMQ MQTT Websocket Client
- Click "Connect".
- Click "Add New Topic Subscription". Type "livingroom" in place of "testtopic/#" and hit Subscribe.
- Say "Alexa, turn on the lights"
- You should see a "True" message posted to the topic!
I'll leave it as an exercise to discover the other topics the example code uses.
Disclaimer: The example code uses a public MQTT server to get you up and running as fast as possible, so don't go publishing your Social Security Number to a test topic!
Step 4: (bonus) Using Multiple Echos & Dealing With Echoes
If you've fallen in love with your newfound Echo powers, you might be interested in using more than one Echo. You'll run into two issues doing so - and here are the solutions for both:
Knowing where the Echo is. You don't want the bedroom Echo to turn on the kitchen lights, but these things don't exactly have GPS built in. Instead, you can use the IP address of each Echo to offer it a different set of commands and controls.
Check out fauxmo_mqtt_example.py for one solution to this. I recorded the IP address seen when I ran fauxmo_minimal.py and kept it as a constant. Then whenever I want different echos to have different responses to the same command, I compare the IP against client_address in the handler's act() function.
Echoes from other Echos. The microphones on the Echo are so sensitive that they'll often pick you up from a room away - even with music playing! While incredibly convenient, it also becomes a problem when you have multiple Echos around the house.
To solve this, I added a "debounce" function to the code (see debounce_handler.py) that prevents the same command from being called multiple times in quick succession. So, if the bedroom AND kitchen Echos hear you, only the first one to submit the command will execute. Whichever Echo hears you loudest & is closest to you processes the message faster, submits the network request faster, and has its request processed - while all the Echos that hear quieter echoes take longer to process and get debounced. Voila! The debounce function is built in, so there's actually nothing extra you need to do here - it works out of the box.
Step 5: That's All, Folks!
You now have the skills to control any device in your home with your voice using the Amazon Echo. Go make incredible things!
If you like this Instructable, don't forget to favorite it and follow us on Facebook
Inspired by @MakerMusings' fauxmo control framework.

Participated in the
Raspberry Pi Contest

Participated in the
Remix 2.0 Contest
113 Comments
Question 4 years ago on Step 1
Hello I think that the script is running fine but when I ask "Alexa: find my devices" she says it could take 45 seconds and comes back with no devices found.
I am very new to this whole Echo thing but do I have to go and by a WeMo switch as my device so that she sees one? because i don't have any device connected for her to find.
what would be an example of a device i could hook up so she could see something?
thanks J
Question 4 years ago
Has anyone got this working from a VirtualBox Ubuntu? Was just trying this to see if it works with the new 3rd-gen Dot but my device isn't being discovered.
I can ping the server just fine and the service is running (got the diagnostics) but Alexa can't find it (running the example-minimal.py script).
Question 5 years ago
This is really nice and works like a charm, thanks. However, if I wanted to execute several Python scripts on the RPi using Alexa voice commands, I guess this solution couldn't be tweaked, right?
5 years ago on Introduction
I would like to see instructions on this using windows 10 OS .
Thank you
5 years ago
Hi and thank you for the great tutorial!
How do I add more than one device to the configuration.
Simply running the fauxmo in 2 instances fails due to the same address already in use.
Bests
6 years ago
exactly what I searched for!
I just want to execute a sudo command to execute a python script "device-on.py" or "device-off.py".
How can I acchieve that? I really dont know.
Reply 5 years ago
Hi Geomi (and also, kinda, Lazerdave)!
I also just wanted something to execute a python script when I say "Alexa, device on" or "Alexa, device off"! I am a REAL amateur and know pretty much nothing of linux or python, but I figured out how to make this script do that on a raspberry pi!
1) Change directories into the folder that has the file named "fauxmo.py".
2) Edit that file by typing "nano fauxmo.py"
a) On the line underneath "import logging" add a new line called "import os"
b) Hold the Control and the _ key and when it asks which line you want to go to, go to line 228
c) Insert a line here -- just below where it says "print "On" and just above where it says "succes = self.action_handler.on(client_address[0], self.name"
Make the newly inserted line say (without the quotes) "os.system('/home/craig/echo/nameofyourscrpt.py argument1 argument2 etc')
1) Don't use the quotation marks, but DO use the single quote marks inside the parentheses.
2) change the /home/craig/echo . . . to wherever the script is that you want to run.
3) Of course, change the part where I wrote "nameofyourscript.py" to whatever the actual name of your script is. Also, if your script needs arguments at the end of it (like mine did) insert them following the name of your script -- just as if you were at a command prompt typing the command.
4) It is important that this new line "line up" vertically with the line above it. That is, in the "os.system . . " part of your new line, the letter o should fall directly under the "p" in the line above that says "print". Likewise, you'll need to make the line below your new line align with your newly inserted line by moving your cursor there and hitting 'tab' twice.
5) Insert a similar line about six lines down, again between the 'print' and 'success' lines. This is where you'll insert the script that you want to run when you say "Alexa, turn device off"!
6) Hit CTRL-O (that's the letter "oh") and then CTRL-X to close out editing the file.
Run the "python example-minimal.py" command and try it out.
Note that of you want to change the name of your "device" you can edit the "example-minimal.py" just as we did above, but change the word 'device' on line 27 to 'light' or 'switch' or whatever it is you want to call it! Then CTRL-O and CTRL-X again.
I hope this helps someone, since I spent an awful lot of time trying to figure it out! I now have a Raspberry Pi that operates as a wifi-to-bluetooth LE 'bridge' for operating a "switchmate". My switchmate was controlling a switch that has no power to the 'mains', so I really needed this to be able to automate the switch! Thanks to the original poster for the scripts!
Laserdave - I do not think there is a way to run four separate scripts, since I think the only states are 'on' or 'off', but as I mentioned - I am REALLY an amateur! Good luck!
Reply 5 years ago
Note that I messed up my directions above. There is no "PRINT" line around line 228! I had added that as part of my own testing to get this stuff working.
Just add a line to run your script above the "succes = self.action_handler.on(client_address[0], self.name" and "succes = self.action_handler.off(client_address[0], self.name" lines, respectively and you'll be good!
Reply 6 years ago
Please read the comments below!
I write it her "kevstone122 -->NathanG99"
Total instruction!
Best regards
Kevin
Reply 6 years ago
Kannst du mir bitte ein Skript erstellen mit dem ich mehrere GPIO Pins über Alexa steuern kann denn der den du an Nathan geschrieben hast funktioniert irgendwie nicht und ausserdem versteh ich ih nicht xD danke LG Nico
PS: Wenn du willst kannst du mich über Eamil anschreiben: hihionio.mail@gmail.com
Reply 6 years ago
Hallo. Tut mir leid für die späte Antwort. Hatte kaum Zeit mehr dafür.
Ist das Problem noch aktuell?
Ich werde beides machen. Dir eine email schreiben, damit du direkt das Python file hast und ebenso hier posten, damit andere Leute etwas davon haben die sich noch dafür interessieren:
""" fauxmo_minimal.py - Fabricate.IO
This is a demo python file showing what can be done with the debounce_handler.
The handler prints True when you say "Alexa, device on" and False when you say
"Alexa, device off".
If you have two or more Echos, it only handles the one that hears you more clearly.
You can have an Echo per room and not worry about your handlers triggering for
those other rooms.
The IP of the triggering Echo is also passed into the act() function, so you can
do different things based on which Echo triggered the handler.
"""
########################################################################################
"""KESJI-HOME-AUTOMATISATION script!
Das ist ein script von Kevin Steindl und mehrere Lampen auf einem einzigen Raspberry
simulieren zu koennen. Software Funktionen wie Trigger, ON und OFF wurden ebenfalls
ergaenzt.
Es koennen unbeschraenkt Geraete definiert werden die alexa nachher auch findet und
schalten kann.
"""
########################################################################################
import fauxmo
import logging
import time
import RPi.GPIO as GPIO
import urllib
import sys #Eventuell fuer Logfile notwendig
#Log File Pfad
logfile = '/home/kevin/Spracherkennung-Logfile.log'
hilfe = 0
Clientname = {"leer"}
zaehler = 0
#Weblinks:
ArduinoON = 'http://10.0.1.12/?1=EIN'
ArduinoOFF = 'http://10.0.1.12/?1=AUS'
#GPIO warnings deaktivieren!
GPIO.setwarnings(False)
#GPIO's zuerst alle einmal als Ausgang definieren
GPIO.setmode(GPIO.BCM)
GPIO.setup(2,GPIO.OUT)
GPIO.setup(3,GPIO.OUT)
GPIO.setup(4,GPIO.OUT)
GPIO.setup(5,GPIO.OUT)
GPIO.setup(6,GPIO.OUT)
GPIO.setup(7,GPIO.OUT)
GPIO.setup(8,GPIO.OUT)
GPIO.setup(9,GPIO.OUT)
GPIO.setup(10,GPIO.OUT)
GPIO.setup(11,GPIO.OUT)
GPIO.setup(12,GPIO.OUT)
GPIO.setup(13,GPIO.OUT)
GPIO.setup(14,GPIO.OUT)
GPIO.setup(15,GPIO.OUT)
GPIO.setup(16,GPIO.OUT)
GPIO.setup(17,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
GPIO.setup(19,GPIO.OUT)
GPIO.setup(20,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)
GPIO.setup(22,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)
GPIO.setup(26,GPIO.OUT)
GPIO.setup(27,GPIO.OUT)
#GPIO Ausgange zuerst alle einmal ausschalten (True beddeutet bei der Relais Platine OFF)
GPIO.output(2,True)
GPIO.output(3,True)
GPIO.output(4,True)
GPIO.output(5,True)
GPIO.output(6,True)
GPIO.output(7,True)
GPIO.output(8,True)
GPIO.output(9,True)
GPIO.output(10,True)
GPIO.output(11,True)
GPIO.output(12,True)
GPIO.output(13,True)
GPIO.output(14,True)
GPIO.output(15,True)
GPIO.output(16,True)
GPIO.output(17,True)
GPIO.output(18,True)
GPIO.output(19,True)
GPIO.output(20,True)
GPIO.output(21,True)
GPIO.output(22,True)
GPIO.output(23,True)
GPIO.output(24,True)
GPIO.output(25,True)
GPIO.output(26,True)
GPIO.output(27,True)
#######################################################################
###################Unterprogramme definieren hier######################
#######################################################################
#Trigger Funktion um eine gewisse Zeit eine 1 zu senden!
def Trigger(Portnumber,Triggertime):
GPIO.output(Portnumber,False)
print "Output", Portnumber,"eingeschalten"
time.sleep(Triggertime)
print "Output", Portnumber,"ausgeschalten"
GPIO.output(Portnumber,True)
#Einmaliges Einschalten
def ON(Portnumber):
GPIO.output(Portnumber,False)
print "Output",Portnumber,"eingeschalten"
#Einmaliges Ausschalten
def OFF(Portnumber):
GPIO.output(Portnumber,True)
print "Output", Portnumber, "ausgeschalten"
# function to save log messages to specified log file
def log(msg):
# open the specified log file
file = open(logfile,"a")
# write log message with timestamp to log file
file.write("%s: %s\n" % (time.strftime("%d.%m.%Y %H:%M:%S"), msg))
# close log file
file.close
#############Hauptprogramm start#########################################
log("#######################Raspberry mit Wemo Client Software wurde gestartet##############################")
from debounce_handler import debounce_handler
logging.basicConfig(level=logging.DEBUG)
class device_handler(debounce_handler):
"""Publishes the on/off state requested,
and the IP address of the Echo making the request.
"""
#Alle verfuegbaren Geraete hier definieren
TRIGGERS = {"Licht": 52000,
"Jalousine": 52001,
"Romantik": 52002,
"Normal": 52003,
"Party": 52004,
"Vorgarten": 52005,
"Kueche Licht": 52006}
log("Alle Geraete initialisiert")
#Diese 4 Dinge werden nach der Erkennung zurueckgemeldet:
#self: Als ich es mit print getestet habe bekam ich diesen Text hinaus: <__main__.device_handler object at 0x76516bf0>
#client_adress: IP Adresse von dem ECHO oder ECHODOT der es gesendet hat
#State: Erkannter Status der von der Stimme erkannt wurde. True oder False
#Name: Der name der erkannt wurde. Muss ein Name von der "TRIGGERS" Liste sein!
def act(self, client_address, state, name):
#Erzeuge Client Name
if client_address == "10.0.1.184":
client_address = "1"
Clientname = "Amazon Dot - Wohnzimmer"
elif client_address == "10.0.1.43":
client_address = "2"
Clientname = "Amazon Echo - Schlafzimmer"
#Schalte Funktion je nach erkanntem Wort
#Geraet 1
if client_address == "1" #Amazon Dot - Wohnzimmer
if name == "Licht":
print "Das Licht im Wohnzimmer ist:", state, "-->Gesendet von", Clientname, ":", client_address
# create new log message
log("Licht im Wohnzimmer Trigger gesendet")
hilfe=1
Trigger(14,0.5)
if name == "Jalousine":
print "Jalousine im Wohnzimmer ist:", state, "-->Gesendet von", Clientname, ":", client_address
log("Jalousine im Wohnzimmer Trigger gesendet")
hilfe=1
Trigger(15,0.5)
#Geraet 2
if client_address == "2" #Amazon Dot - Wohnzimmer
if name == "Licht":
print "Das Licht im Schlafzimmer ist:", state, "-->Gesendet von", Clientname, ":", client_address
# create new log message
log("Licht im Schlafzimmer Trigger gesendet")
hilfe=1
Trigger(2,0.5)
if name == "Jalousine":
print "Jalousine im Schlafzimmer ist:", state, "-->Gesendet von", Clientname, ":", client_address
log("Jalousine im Schlafzimmer Trigger gesendet")
hilfe=1
Trigger(3,0.5)
if name == "Vorgarten":
print "Der Vorgarten ist:", state, "-->Gesendet von", Clientname, ":", client_address
if state == 1:
log("Vorgarten wurde eingeschalten")
content = urllib.urlopen(ArduinoON).read()
elif state == 0:
log("Vorgarten wurde ausgeschalten")
content = urllib.urlopen(ArduinoOFF).read()
hilfe=1
if name == "Kueche Licht":
print "Die Kueche ist:", state, "-->Gesendet von", Clientname, ":", client_address
hilfe=1
if GPIO.input(18) == 1:
ON(18)
log("Kueche wurde eingeschalten")
else:
OFF(18)
log("Kueche wurde ausgeschalten")
if hilfe == 0:
print "Fehler nicht verstanden"
hilfe = 0
return True
if __name__ == "__main__":
# Startup the fauxmo server
fauxmo.DEBUG = True
p = fauxmo.poller()
u = fauxmo.upnp_broadcast_responder()
u.init_socket()
p.add(u)
# Register the device callback as a fauxmo handler
d = device_handler()
for trig, port in d.TRIGGERS.items():
fauxmo.fauxmo(trig, u, p, None, port, d)
# Loop and poll for incoming Echo requests
logging.debug("Entering fauxmo polling loop")
while True:
try: # Allow time for a ctrl-c to stop the process
if (zaehler <= 100):
zaehler = zaehler + 1
else:
zaehler = 0
p.poll(50) #Standard lWert liegt bei 100
time.sleep(0.05) #Standard Wert liegt bei 0.1
print "Warte auf Spracheingabe: ", zaehler
except Exception, e:
logging.critical("Critical exception: " + str(e))
break
5 years ago
Hi, thank you for code, but my Echo could not find any smart devices. Yes - they are in the same WIFI. I checked twice. UPnP is on.
Reply 5 years ago
Hi, I'm having same problem... Did you were able to find the solution?
Reply 5 years ago
I ended up fixing mine, but I am unsure exactly how; however, I narrowed down a couple things I did.
A) I manually restarted the network
B) Made sure the network was given more IP address
1) I actually figure it was this one considering it only had 32 IPs that could be assigned, and, as such, my entire family of 7 easily dominated the network with all of their devices.
Reply 5 years ago
I am having the same issue
5 years ago
installed and run scripts, however, my Echo is not finding any devices? any ideas please would be great?
6 years ago
First off, thanks for the code. Got it installed and working... well mostly. I have 4 echoes (2 full size and 2 dots) and the problem is that the identified client address seems to randomly be one of the 4 IP echo addresses (in my home network). I am not consistently getting a specific IP address for a given echo. Also, this is not an issue with multiple echoes picking up the voice command - they are all acoustically separated. I have a feeling that when a command is received by one echo via voice, it gets processed in the could and the response from the cloud is sent back to one of the echoes within the same LAN which then forwards the command to the fauxmo. If that is the case I guess nothing can be done within the fauxmo code to fix this problem.
Reply 6 years ago
I have exactly the same problem. I used the starter code and extend it with tip address in the functions. So i want to say "Alexa, turn the light on" and if i am in the living room i mean this light and if i am in the bedroom i mean this light. But the ip address isn't correct. sometimes from this dot and sometimes from the other dot. If i disconnect once of both, the ip adress will be correct....Sure only one device is online!
Reply 6 years ago
Any ideas for this problem?
Reply 5 years ago
Any solution for this problem.