Home Automation With Amazon Echo Voice Control

164,400

497

112

Published

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:

  1. An Amazon Echo that's set up with Amazon's instructions
  2. A Raspberry Pi or other computer running Linux
  3. 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:

  1. Use pip to install MQTT by opening up a command window and typing: pip install paho-mqtt
  2. You can now run the test MQTT file with python fauxmo_mqtt_example.py
  3. Open up a web browser and browse to the HiveMQ MQTT Websocket Client
  4. Click "Connect".
  5. Click "Add New Topic Subscription". Type "livingroom" in place of "testtopic/#" and hit Subscribe.
  6. Say "Alexa, turn on the lights"
  7. 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.

2 People Made This Project!

Recommendations

  • Casting Contest

    Casting Contest
  • Oil Contest

    Oil Contest
  • Make it Move Contest

    Make it Move Contest
user

We have a be nice policy.
Please be positive and constructive.

Tips

Questions

112 Comments

I would like to see instructions on this using windows 10 OS .

Thank you

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

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.

5 replies

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!

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!

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

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

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.

3 replies

Hi, I'm having same problem... Did you were able to find the solution?

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.

installed and run scripts, however, my Echo is not finding any devices? any ideas please would be great?

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.

3 replies

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!

Any solution for this problem.

Hello all together!

I have an important question:

After the line "def act(self, client_address, state, name):" i should get back the client_adress (ip adress) of the Echo which hears the sound.
So now i buy the Echo and also the Echo dot. Both of them have different IP adress, but the client_adress is sometimes this and sometimes the other one.

The two Echos are in different levels in the house and so they don't here each other. The feedback of the client adress is not always correct.
Has somebody the same problem?
I want to add some general functions like "light", "Szene" and "Sound" and automatically with the command "light on" the light in the room where the Echo is placed goes on. If i go in another room and say "light on" it will also switch on the correct room because i know the IP adress of this room/echo.

But this doesn't work. Has somebody an idea why this feedback is not working correct? If I switch off one off both immediatelly it will work correct and the room for this IP adress get controlled.
If both are online it is sometimes this ip adress and somethimes the other adress when i always speak with the same Echo.

Thank you!
Best regards
Kevin

2 replies

have you found a solution for the IP address of the calling echo ? mine returns the same IP address no matter which echo is listening... thanks

no at the moment i didn't found the problem. I already ask some friend to help me, but till now nothing found.
I will still follow the problem!

Please give me feedback, if you find something!!!