Fauxmo Alexa Delights

Amazon EchoI’m going to cut a very long story short here.  I’ve been looking at ESP8266 emulations of WEMOs because up to now this seems to be a popular device to emulate when using with your talking Amazon Echo. If anyone wants to come up with something that will take ANY word, not just ON or OFF – please do feel free to do the hard work. In another article, I described how, with the aid of a small SKILL at the Amazon end, an SSL certificate and some Node-Red code, we managed to make a generalised system to extract words out of Echo – and that is controlling my heating and all sorts right now -  marvellous. If you’re not up to speed with ECHO, MQTT or NODE-RED see earlier blogs in here.

Simple On Off

But what if you just want ON and OFF with no HTTPS, no messing at the Amazon end?  I checked out ESP8266 emulations. AWFUL. I’ll not mention names and I’m sure this was just done as a demo – but the one I tested was written in Arduino/ESP code – connected to WIFI and acted as an ON/OFF Wemo – MARVELOUS. Except that with the first sign of WIFI trouble – it fell over and died – absolutely no attempt at making it work regardless. Well as you know, WIFI dies from time to time. Bin.

So what next?

I found something others will have spotted called FAUXMO which is basically a single Python script –that emulates one or more WEMO type devices. At first it did not work – so half a day later having learned enough Python to get me by I realised that this was intended to call web pages – to turn things on and off. I understood there was an MQTT version of it – but that a friend of mine was having trouble getting that working – so  - I decided to go for broke and modify the original.

All you need here is the Pi or similar equipped with MQTT and with Python installed – Node-Red is not needed. Indeed once you see how this works – it would be very easy to take the cheapest of these little SBCs – the FriendlyArm NEO for example and make it look like several devices – instead of MQTT you could turn ports on and off in Python.

Cheapest multi-output Alexa-enabled device on the planet?

Orange Pi ZeroBefore I go further – you might have a simple requirement – far simpler than we usually cover in here – a single box that “does it all”, talking to Amazon Alexa with multiple outputs looking like multiple devices… well, the Orange Pi ZERO available at under £9 (inc shipping) from AliExpress could just be the ticket? Install Armbian, MQTT and Python – and… read on.

PAHO Mqtt

You need a client called Paho MQTT to bring MQTT to Python… so here’s what I did in order… we’re looking at a Pi or similar, running Node-Red and MQTT broker. In my case with username and password.

sudo pip install paho-mqtt

Seconds later, done – MQTT now available inside Python – that was easy.

I had to add a header into the code – to import mqtt – and I had to define username, password, mqtt address.

That all went into the top of the file and should be pretty obvious.

I then modified some code – and the definitions of two sample devices – “kitchen lights” and “bedroom lights”.

Here are the modifications.

Top:

import paho.mqtt.client as paho

mqtt_host="192.168.aa.bb"
mqtt_user="xxxxxxx"
mqtt_pass="yyyyyyyyy"

Change to how recognised terms are actually used

class rest_api_handler(object):
    def __init__(self, on_cmd, off_cmd):
        self.on_cmd = on_cmd
        self.off_cmd = off_cmd

    def on(self):
        dbg(self.on_cmd)
        topic,payload=self.on_cmd.split("|")
        client.publish(topic,payload,0,0)
        return 200

    def off(self):
        dbg(self.off_cmd)
        topic,payload=self.off_cmd.split("|")
        client.publish(topic,payload,0,0)
        return 200

And finally the bit you're interested in - device definitions... you only have to change the user settings at the top then this lot.

FAUXMOS = [
    ['bedroom lights', rest_api_handler('toesp/bedlights|{out0:1}', 'toesp/bedlights|{out0:0}')],
    ['kitchen lights', rest_api_handler('toesp/kitchenlights|{out0:2}', 'toesp/kitchenlights|{out0:3}')],
	]

So what you’re looking at are the words that Alexa will accept (“kitchen lights” for example) followed by ON OR OFF. The two following strings are MQTT topic and PAYLOAD separated by | for firstly ON and secondly OFF.

As you can see it is easy to add new devices – you do with the MQTT what you will – in my case this would be talking directly to devices – more likely I’ll fire instructions off that Node-Red can handle for manual override of lighting etc.

To get this all to work you need to be running the program and say “Alexa find devices” to your ECHO – it will find the devices and you’re ready to go. If you make changes – restart the program – re-find devices.

And here  is the complete – modified Python code – complete with the original author info – after all I didn’t make THAT many changes even if it did end up taking me all day.

Don’t worry about it looking over-powering – you only need to know about the stuff above – the rest is just a case of pasting into into a file.

#!/usr/bin/env python

"""
The MIT License (MIT)
Copyright (c) 2015 Maker Musings
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

# For a complete discussion, see http://www.makermusings.com

import email.utils
import requests
import select
import socket
import struct
import sys
import time
import urllib
import uuid
import paho.mqtt.client as paho

mqtt_host="192.168.aa.bb"
mqtt_user="xxxxxxxx"
mqtt_pass="yyyyyyy"


# This XML is the minimum needed to define one of our virtual switches
# to the Amazon Echo

SETUP_XML = """<?xml version="1.0"?>
<root>
  <device>
    <deviceType>urn:MakerMusings:device:controllee:1</deviceType>
    <friendlyName>%(device_name)s</friendlyName>
    <manufacturer>Belkin International Inc.</manufacturer>
    <modelName>Emulated Socket</modelName>
    <modelNumber>3.1415</modelNumber>
    <UDN>uuid:Socket-1_0-%(device_serial)s</UDN>
  </device>
</root>
"""


DEBUG = False

def dbg(msg):
    global DEBUG
    if DEBUG:
        print msg
        sys.stdout.flush()


# A simple utility class to wait for incoming data to be
# ready on a socket.

class poller:
    def __init__(self):
        if 'poll' in dir(select):
            self.use_poll = True
            self.poller = select.poll()
        else:
            self.use_poll = False
        self.targets = {}

    def add(self, target, fileno = None):
        if not fileno:
            fileno = target.fileno()
        if self.use_poll:
            self.poller.register(fileno, select.POLLIN)
        self.targets[fileno] = target

    def remove(self, target, fileno = None):
        if not fileno:
            fileno = target.fileno()
        if self.use_poll:
            self.poller.unregister(fileno)
        del(self.targets[fileno])

    def poll(self, timeout = 0):
        if self.use_poll:
            ready = self.poller.poll(timeout)
        else:
            ready = []
            if len(self.targets) > 0:
                (rlist, wlist, xlist) = select.select(self.targets.keys(), [], [], timeout)
                ready = [(x, None) for x in rlist]
        for one_ready in ready:
            target = self.targets.get(one_ready[0], None)
            if target:
                target.do_read(one_ready[0])
 

# Base class for a generic UPnP device. This is far from complete
# but it supports either specified or automatic IP address and port
# selection.

class upnp_device(object):
    this_host_ip = None

    @staticmethod
    def local_ip_address():
        if not upnp_device.this_host_ip:
            temp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            try:
                temp_socket.connect(('8.8.8.8', 53))
                upnp_device.this_host_ip = temp_socket.getsockname()[0]
            except:
                upnp_device.this_host_ip = '127.0.0.1'
            del(temp_socket)
            dbg("got local address of %s" % upnp_device.this_host_ip)
        return upnp_device.this_host_ip
        

    def __init__(self, listener, poller, port, root_url, server_version, persistent_uuid, other_headers = None, ip_address = None):
        self.listener = listener
        self.poller = poller
        self.port = port
        self.root_url = root_url
        self.server_version = server_version
        self.persistent_uuid = persistent_uuid
        self.uuid = uuid.uuid4()
        self.other_headers = other_headers

        if ip_address:
            self.ip_address = ip_address
        else:
            self.ip_address = upnp_device.local_ip_address()

        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind((self.ip_address, self.port))
        self.socket.listen(5)
        if self.port == 0:
            self.port = self.socket.getsockname()[1]
        self.poller.add(self)
        self.client_sockets = {}
        self.listener.add_device(self)

    def fileno(self):
        return self.socket.fileno()

    def do_read(self, fileno):
        if fileno == self.socket.fileno():
            (client_socket, client_address) = self.socket.accept()
            self.poller.add(self, client_socket.fileno())
            self.client_sockets[client_socket.fileno()] = client_socket
        else:
            data, sender = self.client_sockets[fileno].recvfrom(4096)
            if not data:
                self.poller.remove(self, fileno)
                del(self.client_sockets[fileno])
            else:
                self.handle_request(data, sender, self.client_sockets[fileno])

    def handle_request(self, data, sender, socket):
        pass

    def get_name(self):
        return "unknown"
        
    def respond_to_search(self, destination, search_target):
        dbg("Responding to search for %s" % self.get_name())
        date_str = email.utils.formatdate(timeval=None, localtime=False, usegmt=True)
        location_url = self.root_url % {'ip_address' : self.ip_address, 'port' : self.port}
        message = ("HTTP/1.1 200 OK\r\n"
                  "CACHE-CONTROL: max-age=86400\r\n"
                  "DATE: %s\r\n"
                  "EXT:\r\n"
                  "LOCATION: %s\r\n"
                  "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
                  "01-NLS: %s\r\n"
                  "SERVER: %s\r\n"
                  "ST: %s\r\n"
                  "USN: uuid:%s::%s\r\n" % (date_str, location_url, self.uuid, self.server_version, search_target, self.persistent_uuid, search_target))
        if self.other_headers:
            for header in self.other_headers:
                message += "%s\r\n" % header
        message += "\r\n"
        temp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        temp_socket.sendto(message, destination)
 

# This subclass does the bulk of the work to mimic a WeMo switch on the network.

class fauxmo(upnp_device):
    @staticmethod
    def make_uuid(name):
        return ''.join(["%x" % sum([ord(c) for c in name])] + ["%x" % ord(c) for c in "%sfauxmo!" % name])[:14]

    def __init__(self, name, listener, poller, ip_address, port, action_handler = None):
        self.serial = self.make_uuid(name)
        self.name = name
        self.ip_address = ip_address
        persistent_uuid = "Socket-1_0-" + self.serial
        other_headers = ['X-User-Agent: redsonic']
        upnp_device.__init__(self, listener, poller, port, "http://%(ip_address)s:%(port)s/setup.xml", "Unspecified, UPnP/1.0, Unspecified", persistent_uuid, other_headers=other_headers, ip_address=ip_address)
        if action_handler:
            self.action_handler = action_handler
        else:
            self.action_handler = self
        dbg("FauxMo device '%s' ready on %s:%s" % (self.name, self.ip_address, self.port))

    def get_name(self):
        return self.name

    def handle_request(self, data, sender, socket):
        if data.find('GET /setup.xml HTTP/1.1') == 0:
            dbg("Responding to setup.xml for %s" % self.name)
            xml = SETUP_XML % {'device_name' : self.name, 'device_serial' : self.serial}
            date_str = email.utils.formatdate(timeval=None, localtime=False, usegmt=True)
            message = ("HTTP/1.1 200 OK\r\n"
                       "CONTENT-LENGTH: %d\r\n"
                       "CONTENT-TYPE: text/xml\r\n"
                       "DATE: %s\r\n"
                       "LAST-MODIFIED: Sat, 01 Jan 2000 00:01:15 GMT\r\n"
                       "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
                       "X-User-Agent: redsonic\r\n"
                       "CONNECTION: close\r\n"
                       "\r\n"
                       "%s" % (len(xml), date_str, xml))
            socket.send(message)
        elif data.find('SOAPACTION: "urn:Belkin:service:basicevent:1#SetBinaryState"') != -1:
            success = False
            if data.find('<BinaryState>1</BinaryState>') != -1:
                # on
                dbg("Responding to ON for %s" % self.name)
                success = self.action_handler.on()
            elif data.find('<BinaryState>0</BinaryState>') != -1:
                # off
                dbg("Responding to OFF for %s" % self.name)
                success = self.action_handler.off()
            else:
                dbg("Unknown Binary State request:")
                dbg(data)
            if success:
                # The echo is happy with the 200 status code and doesn't
                # appear to care about the SOAP response body
                soap = ""
                date_str = email.utils.formatdate(timeval=None, localtime=False, usegmt=True)
                message = ("HTTP/1.1 200 OK\r\n"
                           "CONTENT-LENGTH: %d\r\n"
                           "CONTENT-TYPE: text/xml charset=\"utf-8\"\r\n"
                           "DATE: %s\r\n"
                           "EXT:\r\n"
                           "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
                           "X-User-Agent: redsonic\r\n"
                           "CONNECTION: close\r\n"
                           "\r\n"
                           "%s" % (len(soap), date_str, soap))
                socket.send(message)
        else:
            dbg(data)

    def on(self):
        return False

    def off(self):
        return True


# Since we have a single process managing several virtual UPnP devices,
# we only need a single listener for UPnP broadcasts. When a matching
# search is received, it causes each device instance to respond.
#
# Note that this is currently hard-coded to recognize only the search
# from the Amazon Echo for WeMo devices. In particular, it does not
# support the more common root device general search. The Echo
# doesn't search for root devices.

class upnp_broadcast_responder(object):
    TIMEOUT = 0

    def __init__(self):
        self.devices = []

    def init_socket(self):
        ok = True
        self.ip = '239.255.255.250'
        self.port = 1900
        try:
            #This is needed to join a multicast group
            self.mreq = struct.pack("4sl",socket.inet_aton(self.ip),socket.INADDR_ANY)

            #Set up server socket
            self.ssock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
            self.ssock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

            try:
                self.ssock.bind(('',self.port))
            except Exception, e:
                dbg("WARNING: Failed to bind %s:%d: %s" , (self.ip,self.port,e))
                ok = False

            try:
                self.ssock.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,self.mreq)
            except Exception, e:
                dbg('WARNING: Failed to join multicast group:',e)
                ok = False

        except Exception, e:
            dbg("Failed to initialize UPnP sockets:",e)
            return False
        if ok:
            dbg("Listening for UPnP broadcasts")

    def fileno(self):
        return self.ssock.fileno()

    def do_read(self, fileno):
        data, sender = self.recvfrom(1024)
        if data:
            if data.find('M-SEARCH') == 0 and data.find('urn:Belkin:device:**') != -1:
                for device in self.devices:
                    time.sleep(0.1)
                    device.respond_to_search(sender, 'urn:Belkin:device:**')
            else:
                pass

    #Receive network data
    def recvfrom(self,size):
        if self.TIMEOUT:
            self.ssock.setblocking(0)
            ready = select.select([self.ssock], [], [], self.TIMEOUT)[0]
        else:
            self.ssock.setblocking(1)
            ready = True

        try:
            if ready:
                return self.ssock.recvfrom(size)
            else:
                return False, False
        except Exception, e:
            dbg(e)
            return False, False

    def add_device(self, device):
        self.devices.append(device)
        dbg("UPnP broadcast listener: new device registered")


# This is an example handler class. The fauxmo class expects handlers to be
# instances of objects that have on() and off() methods that return True
# on success and False otherwise.
#
# This example class takes two full URLs that should be requested when an on
# and off command are invoked respectively. It ignores any return data.
# 
# Clearly somewhat modified by PS to take in a string - split in two and send out to MQTT
class rest_api_handler(object):
    def __init__(self, on_cmd, off_cmd):
        self.on_cmd = on_cmd
        self.off_cmd = off_cmd

    def on(self):
        dbg(self.on_cmd)
        topic,payload=self.on_cmd.split("|")
        client.publish(topic,payload,0,0)
        return 200

    def off(self):
        dbg(self.off_cmd)
        topic,payload=self.off_cmd.split("|")
        client.publish(topic,payload,0,0)
        return 200


# Each entry is a list with the following elements:
#
# name of the virtual switch
# object with 'on' and 'off' methods
# port # (optional; may be omitted)

# NOTE: As of 2015-08-17, the Echo appears to have a hard-coded limit of
# 16 switches it can control. Only the first 16 elements of the FAUXMOS
# list will be used.

# Clearly the above is changed. Here we have MQTT commands in the form topic|payload

FAUXMOS = [
    ['bedroom lights', rest_api_handler('toesp/bedlights|{out0:1}', 'toesp/bedlights|{out0:0}')],
    ['kitchen lights', rest_api_handler('toesp/kitchenlights|{out0:2}', 'toesp/kitchenlights|{out0:3}')],
	]


if len(sys.argv) > 1 and sys.argv[1] == '-d':
    DEBUG = True

# Set up our singleton for polling the sockets for data ready
p = poller()

# Set up our singleton listener for UPnP broadcasts
u = upnp_broadcast_responder()
u.init_socket()

# Add the UPnP broadcast listener to the poller so we can respond
# when a broadcast is received.
p.add(u)

# Create our FauxMo virtual switch devices
for one_faux in FAUXMOS:
    if len(one_faux) == 2:
        # a fixed port wasn't specified, use a dynamic one
        one_faux.append(0)
    switch = fauxmo(one_faux[0], u, p, None, one_faux[2], action_handler = one_faux[1])

dbg("Entering main loop\n")

client = paho.Client()
client.username_pw_set(mqtt_user, mqtt_pass)
client.connect(mqtt_host)

while True:
    try:
        # Allow time for a ctrl-c to stop the process
        p.poll(100)
        time.sleep(0.1)
    except Exception, e:
        dbg(e)
        break

client.disconnect()

(if this lot complains about spacings - get the original article and make my changes

So – put the file in a directory – I put it into /home/pi/fauxmo/fauxmo.py and gave the file execute permissions (no idea if that’s needed or not but as I do that with scripts I thought it best - 0754 if you're interested).

I ran the file in the /home/pi/fauxmo folder at a terminal as:

python fauxmo.py –d

The –d is for debug – you can scratch that once you are running – and then find a way to make it run reliably on power up. That is possibly described here:

https://github.com/makermusings/fauxmo  if someone has the working command line for this please do send it in – might save some experimenting.

And that’s it. Great fun and instantly useful without lots of hassle. With Node-Red you could fire the MQTT in to do with what you want – or fire straight to MQTT-accepting ESP8266s (what use are ESPs that DON’T support MQTT you might ask) – or if you look at the chunk of code handling MQTT – you could pull that apart and instead just control ports!!

So here’s a thought – one of our readers was kind enough to remind me that the Orange Pi Zero is now available and it is CHEAP. Normally I’d not touch Orange with a bargepole but the Armbian Jessie implementation seems to be now up to speed. SO - https://www.aliexpress.com/store/product/New-Orange-Pi-Zero-H2-Quad-Core-Open-source-development-board-beyond-Raspberry-Pi/1553371_32760774493.html

Under £9 for the cheapest, might not be that happy running Node-Red but it will certainly run PYTHON and MQTT (well, you don’t even need MQTT for that matter if you just want to control the odd output or send stuff through serial etc)… so for under £9 you could have several Alexa-enabled devices !!! That can’t be bad.

This will no doubt mutate as time goes on!

Facebooktwittergoogle_pluspinterestlinkedin

47 thoughts on “Fauxmo Alexa Delights

    1. Thanks Tony - I did notice it and I am using it right this minute - but the method above is more suited to a minimal situation where you might not have node-red.. though you could use it with Node-Red you're right - the node is most likely the simplest way.
      However - imagine the many SBC's that don't play too well with Node-Red when it comes to GPIO - I2c etc... well if you're using the Python script there's a good chance you could handle that all inside the script - so basically, Python, MQTT and some GPIO control. I'm basically trying to cover as many simple ways to use these gadgets as possible.

  1. hi Peter... as you talked about the Neo, i did a little research... if linux support will be ok, maybe i found better alternatives...

    nanopi neo, only eth, 8$ for 256mb ram, 10$ for 512mb ram, both + shipment, and you already know how costly are friendlyarms shipments...
    http://www.friendlyarm.com/index.php?route=product/product&product_id=132

    nanopi neo air, only wifi, 512mb ram BUT with 8gb emmc embedded, 18$+shipment...
    http://www.friendlyarm.com/index.php?route=product/product&path=69&product_id=151

    a few days ago a new device was presented, orangepi zero, with eth (support for POE!), AND wifi with external antenna:
    orangepi zero, eth+poe+wifi, 256mb ram, 10$ shipped
    https://it.aliexpress.com/item/New-Orange-Pi-Zero-H2-Quad-Core-Open-source-development-board-beyond-Raspberry-Pi/32760774493.html

    orangepi zero, eth+poe+wifi, 512mb ram, 12$ shipped
    https://it.aliexpress.com/item/New-Orange-Pi-Zero-H2-Quad-Core-Open-source-512MB-development-board-beyond-Raspberry-Pi/32761500374.html

    a passive poe injector:
    4 ports, 5$: https://it.aliexpress.com/item/Free-shipping-4-LAN-Ports-Passive-POE-adaptere-Pin-4-5-7-8-Power-Over-Ethernet/32322054334.html
    8 ports, 9$: https://it.aliexpress.com/item/Security-8-port-passive-POE-injector-Power-over-Ethernet-for-IP-Network-Camera/32709350480.html

    what do you think? 🙂

    1. So - despite my comments about Orange and I STILL think their customer service STINKS - thanks to Armbian - it LOOKS like the ZERO might be a good option.... and I have a good use for it.... I've just written a little article about using MQTT and PYTHON only to make devices that look like multiple WEMOs. Your ZERO - even the little one - might just do the job provided it is easy enough to control the ports by PYTHON or similar and that comes back to support - will they dump them on the market - or provide enough support to control the ports, I2c etc from, say Python - now, if they DO then you could make one hell of a voice responding peripheral!!!

      So the cheap one at under £9 might be well suited to the above software - providing multiple devices - possibly even I2C devices (depending on driver availability)... worth a thought.

    2. Yes - I think you are right in all respects - the Orange Pi (note my (new) comments about peripherals - Armbian takes care of the operating system but you'd need to be able to make good use of the ports) the cheapest Orange would do with this code modified to directly handle ports etc... this just keeps getting better.

      Keep firing ideas in here. Very good.

      1. I've written a lib for arduino that handles wemo emulation via wemo. Did it last weekend and it is working just dandy, although you have to manage the wifi yourself (unless you use my other lib ESPmanager.)

        Alexa discovers them all, and turns them on and off quite reliably.

        I started writing the lib with ambitions to have it emulate multiple devices, with callbacks when alexa changes their state, but alas this is too complex for alexa. right now it only supports on/off for wemo. This might change as the wemo can act as a bridge with downstream connected devices... so if alexa works with this this then i can update it. it has a dependency: asyncwebserver from me-no-dev.

        The other slightly annoying thing is that alexa only supports 16 devices max, of wemo. so that might get a little limited... (i now have 11 sonoffs running my own code).

        I have also set up a skill to work with my home automation, but I'm not a fan of having to start the skill every time u want a command... it ends up being a mouthful.

        anyway here are links to the lib.

        https://github.com/sticilface/wemos_arduino

        i should probably rename wemo arduino....

        1. Thank you so much for the feedback Andrew and the link. I have to say I am beginning to wonder about the WIMO emulation... ok, it is very easy to use - and you don't have all that faff that you have with the work we've done using HTTPS - however with the latter - you can put checks for words that are almost like the ones you want - and you can have any arguments - and send voice feedback. With the WEMO you get "OK" - does that mean ok it turned it on - or offer? No way to know.

          I've started thinking about this since I did "Alexa, tell the computer to turn the heating to 14 degrees" - turns out it thought I mean 40 degrees and when I got up the next morning the office was like a sauna. I think it is very important that we get proper feedback from Alexa. I just wish there was a built in skill to simply return the words - without having to go through the secure SSL procedure.

          1. I do agree with you. especially as when you search for the wemo API you get a link saying they've pulled it. so 1 its impossible to find out what this protocol is meant to look like. 2. no future support.

            I think the smart devices is the way forward but again this is plagued (rightly so) by requiring SSL authentication. I looked at creating a nodejs app that might be able to do all this automatically, but i didn't get anywhere. The advantage of making smart device emulation is that you would not have to open the skill every time. you could just say "turn off the computer" and boom.

            I've also had lots of issues with "livingroom" sometimes it is living room others livingroom... so its hit or miss if alexa gets it!

            anyway.. watching this space. i guess alexa will get better with time!

  2. You might also be interested in HA-Brige( https://github.com/bwssytems/ha-bridge ). On a week long visit to the mid-west I used it to tie my Echo Dot to ESP8266's and Node Red by putting in REST-like parameters into HA-Bridge for the ESP8266 devices. IIRC I used Arduino on the ESP8266(NodeMCU).

    It's a bit blurry now since it was my first experience with all of the tech involved except Arduino. As you know, it's fun to be able to instruct Alexa to do things and have Node Red phone apps/pages to do it too. I should have blogged and still have the code(s) on my machine somewhere.

    1. Hi there

      I'll have a play at some point but you might have noticed this earlier article - http://tech.scargill.net/alexa-enlightenment/

      We can do just about anything with this as Node-Red gets complete control of the words coming in - I've just updated it to include a "cancel" option - i.e. if "cancel" is amongst the words spoken - it bombs immediately. Right now I've just completed "Alexa, tell computer to turn the office heating to XX degree" and "Alexa, tell computer to turn on the office lights".

      I was using "shed" instead of office - a more accurate description - but Alexa does NOT like "shed".

      1. Hi Peter,

        Sorry for asking but I may be missing something here. Everything you are asking Alexa to ask your computer to do can be done using either the WEMO Emulator or HA-Bridge directly on your internal network, without SSL. So why go thought all the hoops of setting up SSL?

        1. Hi Mike - I must be missing something here. WEMO emulator as far as I know can only tell things to turn on and off. The Node-Red emulator does that well, sadly with no feedback - you get OK regardless of whether it has turned the lights on or blown the kitchen up - I put this article up for those wanting to miss out on the delights of SSL (having said that - it's not that hard - I'm now trying a free self-certification SSL which is a one-liner thanks to one of the guys in here - but I can't get my router for pass through port 443 for reasons currently escaping me). HA-Bridge - I have to say - unless I'm reading the wrong set of instructions looks a lot more complicated than getting an SSL certificate.

          1. Peter,

            It does look complicated, in fact I was overthinking it also the first time I looked at it. The installation is pretty simple. After installing it you create devices via the ha-bridge webpage. For the purpose of only controlling devices then you have to open the ha-bridge webpage and then select the Manually Add tab. In there you give your device a name, which is the name you are going to tell Alexa to control (E.g. Kitchen light). If you want to sent an MQTT message to node-red then you select program/script from the dropdown below the name, and then you can use mosquitto_pub to send the On, Off and Dim messages to node-red for that device.

            Mike

            1. Ha-Bridge -- Can you have it send at the end, speech back to Dot?

              For example... with my code (other article not this one) - "Echo, ask computer for status of heating" -

              And it will come back and say "the heating is set to 16c and actual is 32c"

              And has anyone figured out how to tell which of two DOTS has actually sent the request (we haven't).
              Or is it just "OK" ??

            2. Mike...

              There seem to be a couple of version of this floating around - can you confirm the URL... I got as far as running a JAVA file - then it got hazy - what do you do then? Lots of assumptions - never heard of MAVEN for example.... Is there a video on Youtube for this particular version?

              1. The one you should use is https://github.com/bwssytems/ha-bridge. there is a rpi example installation on the github link

                this version is actively maintained and it is the only one that allows you to run a script or program in the device tab.

                The device file is actually a json file that can also be manipulated manually in a text editor. the file is kept in the data sub folder where ha-bridge is installed.

                I like your question about the youtube video. that is also the first thing I look for, I am a see it and remember it type of guy as opposed to a read it and forget it. This video shows how to install it on a pi.
                https://youtu.be/3xoQTUJEH2I

                This guy has come up with a way to have Alexa respond but I haven't looked at it too much yes.

                https://youtu.be/9Ilw0f4srE8

                Mike

                1. Ok, got it working - had to install mosquitto clients - and add password etc... got on, off, dim on VERA - purely by experimenting... but that's it - no idea what commands you can fire at the other devices - and all you get back is "ok" - which is fine - but compared to what we've done with the SSL - very much backwards - need more examples .... what would you need to use/fill in to be able to do "up", "down" - and "25 degrees" for example? Ideas?

                  1. Peter,

                    I am unable to confirm if dimming works, as my lights are not dimmable yet, but they will be in a couple off weeks.

                    In any case, from what I understand the payload of the mosquito_pub command should be ${intensity.percent}.

                    And Alexa will respond to the following dim commands.

                    Alexa, brighten to
                    Alexa, dim to
                    Alexa, brighten
                    Alexa, dim
                    Alexa, raise to
                    Alexa, lower to
                    Alexa, set to
                    Alexa, turn up to
                    Alexa, turn down to

                    Ideally I would also like to have Alexa respond, and it would be even better is that could be done without having to configure SSL, which is likely not possible. I will try and reach out to these guys to see how they did it.

                    https://www.youtube.com/watch?v=HpnQ1RTfRLw

                    Mike

                    Mike

                    1. Hi Mike...

                      Ok, I've done a new blog about HA Bridge - thanks to help from you and others. The ${intensity.percent} WORKS! - but only so well. Ask for 30 you get 30. Ask for UP or down and it seems to go up or down maybe 25% - ideal for lights- not so good for the heating - need to know how to control that percentage - OR to differentiate between a fixed value - and an up/down command... Ideas anyone? It does look like fun but the info is all over the place - hence my new blog entry - MQTT setup all in one blog (easy really) - but need to know more about what we can get out of it and if there is ANY chance of telling Alexa to SAY something other than OK. In our SSL project - we return a payload and that is what Alexa says on completion of a command - nice to know if you turned the heating to 25 or 250....

                    2. I think some of these words just get ignored - which is what I do in our more complex coding... reducing "would you please turn the heating up to 25 degrees thank you" ends up as "heating 25" 🙂

          2. BTW, I'm have problems with SSL. It might be the fact the I'm using a DNS forwarder that is not secure. I would be interested in the one liner you are talking about for the self-signed cert.

            Mike

    2. Eveing doug.

      Ok, so I grabbed the java file for ha-bridge and once I figured out how to change the port - ran it... went to the web page - very nice..

      Created a device BRIAN. So it wants web pages for on, off and hue.

      So I need that in Node-Red to fire off to MQTT. I took an HTTP node and a response node and fastened them together - with a debug also attached to the http node - called it testing - so far, so good. BUT I have authentication on Node-red and any nodes after that.

      When I talk directly from Amazon to node- red I do this..

      myuser:mypass@http://myurl.0.0.1:1880/testing

      However - one might expect THIS to work in the on/off/dim argument fields for BRIAN

      myuser:mypass@http://127.0.0.1:1880/testing

      But it doesn't. "turn Brian off" - it knows about Brian - but Brian isn't responding... I simply cannot find examples of this to get it right. Any thoughts?

      I did try Mosquitto - but the example I found gave no-where near enough info to fill the page in.

      1. Peter,

        for MQTT this is what I have in my off URL field

        mosquitto_pub -h (mqtt_ip_address) -t (topic) -m (payload)
        In my case it looks like this

        mosquitto_pub -h 192.168.200.121 -t alexa/kitchenled -m 0

  3. So what does this actually replace? does it run as a hub like the Philips hue?
    If I bung this on my spare Zero, can I remote control any smart devices, like bulbs etc without any other hardware other than the Echo and the Zero?

    1. The short answer is YES. You need the ECHO and your ZERO - clearly with WIFI (Don't know if you're talking about the Pi zero - or the Orange Pi Zero). It can look like several devices - you could for example put a relayboard on the ZERO and have it control several relays.

    2. yes, it acts as a Hue bridge but you have full control. That means you can do standard things or you can trigger custom things you and only you have access through your LAN and/or WLAN and can programatically control. Have an ardruino opening/closing your blinds then you can trigger this.

      The Node Red part I did was because I not only wanted voice control via Alexa but I also wanted tablet/mobile/pc control.

      1. Not quite what i meant - can you use any control words in Alexa or just yes, no, up, down. The point of the way we did it was to be able to use any words...

        So "alexa, tell computer to turn the office heating to 25 degrees"
        or "Alex, tell the computer to turn the office green lights on"

        etc... in other words, Node-Red controls everything after "tell computer to" - and getting spoken feedback.

        I'd assumed that kind of control meant writing a custom skill as we did. All of which would be trivial were it not for the need for SSL. Having said that - it wasn't THAT hard.

        1. Is this the answer to your question Peter

          Here is the table of items to use to tell Alexa what you want to do:

          To do this... Say this...
          ON Commands
          Alexa, turn on
          Alexa, start
          Alexa, unlock
          Alexa, open
          Alexa, boot up
          Alexa, run
          Alexa, arm
          OFF Commands
          Alexa, turn off
          Alexa, stop (this one is tricky to get right)
          Alexa, stop running (also very tricky)
          Alexa, lock
          Alexa, close
          Alexa, shutdown
          Alexa, shut
          Alexa, disarm
          DIM Commands
          Alexa, brighten to
          Alexa, dim to
          Alexa, brighten
          Alexa, dim
          Alexa, raise to
          Alexa, lower to
          Alexa, set to
          Alexa, turn up to
          Alexa, turn down to

  4. Pete - here is something that you will find interesting: a way to collect all the spoken text after the invocation words which is great for having complicated actions.
    Make sure that you set up UK and USA English (may be important)

    To set up, on Alexa Skills kit.
    Amazon, Interaction Model, Intent schema:
    =start=======
    {
    "intents": [
    {
    "intent": "DoCommand",
    "slots": [
    {
    "name": "command",
    "type": "LITERAL"
    }
    ]
    }
    ]
    }
    =end========

    Amazon, Interaction Model, Sample Utterances:
    =start=======
    DoCommand {script parameters|command}
    =end========
    Point the Alexa url to your ssl based node red server.

    The node red flow:
    =start=======
    [{"id":"25c1f771.cb4cf8","type":"http in","z":"fb7ee0c6.9a8538","name":"node red request","url":"/nodered","method":"post","swaggerDoc":"","x":131,"y":166,"wires":[["6231b14.5d0ecd"]]},{"id":"f800833f.667c28","type":"debug","z":"fb7ee0c6.9a8538","name":"spoken text","active":true,"console":"false","complete":"payload","x":840.8889770507812,"y":245.66665649414062,"wires":[]},{"id":"6231b14.5d0ecd","type":"switch","z":"fb7ee0c6.9a8538","name":"Request Type","property":"payload.request.type","propertyType":"msg","rules":[{"t":"eq","v":"LaunchRequest","vt":"str"},{"t":"eq","v":"IntentRequest","vt":"str"},{"t":"eq","v":"SessionEndedRequest","vt":"str"}],"checkall":"true","outputs":3,"x":247.5,"y":246,"wires":[[],["810d4e1e.d25ce8"],[]]},{"id":"810d4e1e.d25ce8","type":"switch","z":"fb7ee0c6.9a8538","name":"Intents","property":"payload.request.intent.name","propertyType":"msg","rules":[{"t":"eq","v":"DoCommand","vt":"str"}],"checkall":"true","outputs":1,"x":428.5,"y":246,"wires":[["e377b9af.c4c5c"]]},{"id":"e377b9af.c4c5c","type":"function","z":"fb7ee0c6.9a8538","name":"Extract commands","func":"msg.payload = msg.payload.request.intent.slots.command.value;\nreturn msg;","outputs":1,"noerr":0,"x":618,"y":246,"wires":[["f800833f.667c28","e47e1db2.f3e51"]]},{"id":"e47e1db2.f3e51","type":"template","z":"fb7ee0c6.9a8538","name":"Format response","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\n \"version\": \"1.0\",\n \"response\": {\n \"outputSpeech\": {\n \"type\": \"PlainText\",\n \"text\": \"{{payload}}\"\n },\n \"shouldEndSession\": true\n }\n}","x":867,"y":287,"wires":[["a55ec883.75ea18"]]},{"id":"a55ec883.75ea18","type":"json","z":"fb7ee0c6.9a8538","name":"","x":943,"y":338,"wires":[["3a8ca2eb.e50ede"]]},{"id":"3a8ca2eb.e50ede","type":"http response","z":"fb7ee0c6.9a8538","name":"","x":1070,"y":338,"wires":[]}]
    =end========

    To use:
    Alexa, ask node red "say hello hello hello 1 2 3"

    Alexa will say the response from Node Red. The nice thing is that all the words are sent to Node Red, not just basic commands. The world is your oyster!. I have had IBM Watson do translations of english spoken words to french - unfortunately the english Alexa is not very good at speaking french.

    Apparently, this routine is a "bug/feature" so it may not work long term.
    Let me know if you need any help.

  5. Going back to Fauxmo for a moment, I can't get Pete's version work correctly...
    ----
    pi@emonpi:~/data $ python fauxmo.py -d
    Listening for UPnP broadcasts
    got local address of 192.168.1.4
    UPnP broadcast listener: new device registered
    FauxMo device 'central heating' ready on 192.168.1.4:39212
    UPnP broadcast listener: new device registered
    FauxMo device 'hot water' ready on 192.162.1.4:48313
    Entering main loop
    Responding to search for central heating
    Responding to search for hot water
    -------
    However, Alexa responds that she can't find any devices. Any ideas?

  6. Hi Pete. Your blog is totally awesome! Thanks for all your efforts.

    I am implementing my own system based on what you have done, and in the process of searching around for Alexa-friendly support I discovered this node-red WeMo emulator (https://github.com/biddster/node-red-contrib-wemo-emulator) that I thought you might like. Each node represents a WeMo device and Alexa discovers them!

    At the other end I am using mochad to control X10 devices via my CM15a. This link has a good quick start: https://www.markvriens.com/raspberry-pi-x10-with-cm15pro-controller

    1. Hi there - thanks for the kind words. The Wemo Emulator there seems only to support on and off. So if you look at my script - I setup HA-Bridge on the same device as Node-Red - this has a nice control panel and you can have it send MQTT to Node-Red or straight to the devices - there are a number of other ways to send stuff - and as well as on-off for as many devices as you want... it also handles up down and set values "turn office heating to 23 degrees" - "turn office heating up 2 degrees" - it works perfectly. Both of these systems fail only when you want some sensible feedback - hence my original article which needs HTTPS on your system and Amazon insist on using the https port (it really does not matter what port you use but they want you to use just the one) - if you do it THAT way which is a little harder - you can basically have Echo fire words at Node-Red - you process them and send back whatever words you want back to Echo - I don't know of other systems that do this. Hence I can say "Echo what is the temperature of the Raspberry Pi" and it can say "The Pi is 32 degrees" - or in fact anything "The pi is pretty hot"...

Leave a Reply

Your email address will not be published. Required fields are marked *