Details on the Echo's interaction with Fauxmo, and how to examine it for debugging.
Tons of information gathered by @makermusings, I strongly recommend you start by reading these:
- https://github.com/makermusings/fauxmo/blob/master/protocol_notes.txt
- http://www.makermusings.com/2015/07/13/amazon-echo-and-home-automation
In summary:
- User tells Echo to "find connected devices" or clicks corresponding button in webapp
- Echo broadcasts "device search" to
239.255.255.250:1900
(UDP) - Fauxmo response includes
LOCATION
ofsetup.xml
endpoint for each "device" in config (UDP) - Echo requests
setup.xml
endpoint at aboveLOCATION
(HTTP) for each device - Fauxmo responds with setup information for each device (HTTP)
- Alexa verbally announces any discovered devices (really wish I could mute this -- set volume to 1 beforehand if I'll be doing it a bunch), and they also show up in the webapp
Once you understand the basic model of interaction, the next step in debugging is to inspect the actual requests and responses.
The following commands require some tools you might not have by default; you
can get them with: sudo apt-get install tcpdump tshark nmap
. Doesn't
matter what you choose regarding the wireshark question you'll get during
installation; just read the warning and make a good decision. On OSX, use
homebrew to install the same.
First, get the IP address of your Echo. If you don't know it:
# Assuming your local subnet is 192.168.27.*
sudo nmap -sP 192.168.27.1/24 | grep -i -B 2 amazon
You should get Nmap scan report for 192.168.27.XXX
-- your Echo IP address.
For the examples below, I'll use 192.168.27.100
as the Echo IP address, and
192.168.27.31
as the Pi's IP address (31 as in 3.14, easier to remember).
Next, we'll check out the info being sent to and from the Echo and Fauxmo. In one window, run Fauxmo in verbose mode. In a second window, run the commands below, and check their output when you tell the Echo to find connected devices.
To get an overview of what's going on, start with tshark
:
sudo tshark -f "host 192.168.27.100" -Y "udp"
# Alternatively, only show the Echo's SEARCH requests:
sudo tshark -f "host 192.168.27.100" -Y "udp contains SEARCH"
# Only show the Fauxmo responses (note still using the Echo's IP):
sudo tshark -f "host 192.168.27.100" -Y "udp contains LOCATION"
Example output for the first command, showing a few sets of SSDP SEARCH sent by the Echo followed by 4 responses by Fauxmo (1 for each device in sample config).
Capturing on 'eth0'
1 0.000000 192.168.27.100 -> 239.255.255.250 SSDP 149 M-SEARCH * HTTP/1.1
2 0.046414 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
3 0.064351 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
4 0.082011 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
5 0.101093 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
6 0.104016 192.168.27.100 -> 239.255.255.250 SSDP 149 M-SEARCH * HTTP/1.1
7 0.151414 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
8 0.171049 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
9 0.191602 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
10 0.199882 192.168.27.31 -> 192.168.27.100 SSDP 428 HTTP/1.1 200 OK
11 0.231841 192.168.27.100 -> 239.255.255.250 SSDP 164 M-SEARCH * HTTP/1.1
12 0.333406 192.168.27.100 -> 239.255.255.250 SSDP 164 M-SEARCH * HTTP/1.1
To get a raw look at all the info, use tcpdump
. I've cleaned up a bunch of
garbage in the below output, but you should still be able to recognize each of
the critical components.
sudo tcpdump -s 0 -i eth0 -A host 192.168.27.100
This should show a ton of detailed info, including all responses sent to / from
the Echo. Replace etho
with your network interface (check with ip link
) and
192.168.27.100
with your Echo's IP address.
The output should start with several of the Echo's UDP based discovery
requests, where you can recognize the UDP
protocol being sent from the Echo
192.168.27.100
to the network's multicast broadcast 239.255.255.250.1900
,
something like:
15:48:39.268125 IP 192.168.27.100.50000 > 239.255.255.250.1900: UDP, length 122
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 15
ST: urn:Belkin:device:**
Below that, you should see Fauxmo's responses, also UDP, one for each device in
the config. This response provides the Echo with the LOCATION
of the device's
setup.xml
.
15:48:39.513741 IP 192.168.27.31.1900 > 192.168.27.100.50000: UDP, length 386
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=86400
DATE: Sun, 24 Apr 2016 21:48:39 GMT
EXT:
LOCATION: http://192.168.27.31:12340/setup.xml
OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01
01-NLS: c66d1ad0-707e-495e-a21a-1d640eed4547
SERVER: Unspecified, UPnP/1.0, Unspecified
ST: urn:Belkin:device:**
USN: uuid:Socket-1_0-2d4ac336-8683-3660-992a-d056b5382a8d::urn:Belkin:device:**
Somewhere below that, you'll see the Echo request each device's setup.xml
(based on the LOCATION
from the prior step), this time TCP instead of UDP.
15:48:39.761878 IP 192.168.27.100.39720 > 192.168.27.31.12341: Flags [P.], seq 1:68, ack 1, win 274, options [nop,nop,TS val 619246756 ecr 140303456], length 67
GET /setup.xml HTTP/1.1
Host: 192.168.27.31:12341
Accept: */*
And somewhere below that, Fauxmo's setup response, for each device in the config, also TCP:
15:48:39.808164 IP 192.168.27.31.12342 > 192.168.27.100.59999: Flags [P.], seq 1:608, ack 68, win 453, options [nop,nop,TS val 140303462 ecr 619246754], length 607
HTTP/1.1 200 OK
CONTENT-LENGTH: 375
CONTENT-TYPE: text/xml
DATE: Sun, 24 Apr 2016 21:48:39 GMT
LAST-MODIFIED: Sat, 01 Jan 2000 00:01:15 GMT
SERVER: Unspecified, UPnP/1.0, Unspecified
X-User-Agent: Fauxmo
CONNECTION: close
<?xml version="1.0"?>
<root>
<device>
<deviceType>urn:Fauxmo:device:controllee:1</deviceType>
<friendlyName>fake hass switch by REST API</friendlyName>
<manufacturer>Belkin International Inc.</manufacturer>
<modelName>Emulated Socket</modelName>
<modelNumber>3.1415</modelNumber>
<UDN>uuid:Socket-1_0-cbc4bc63-e0e2-3a78-8a9f-f0ff7e419b79</UDN>
</device>
</root>
Then, to get a really close look at a request, well go back to tshark
. For
example, we can add the -V
flag to get a ton more info, and add -c 1
(count) to limit to capturing a single packet, and further refine the capture
filter by specifying that we only want to look at packets sent from the Pi
to the Echo.
sudo tshark -f "src 192.168.27.31 and dst 192.168.27.100" -c 1 -V
At the bottom, you should find the Hypertext Transfer Protocol
section
contains the same setup.xml
response we found in the tcpdump
output above.
You can also send requests from another device on the network to check out Fauxmo's responses and ensure that they're getting through the network. For example, to simulate the Echo's device search, run the following from another device on the network, in two different windows:
# Seems to work with `nc.traditional` on Raspberry Pi, not yet working for me on OSX
# Window 1: Listen for response on port 12345 (should show up once second command is sent)
nc.traditional -l -u -p 12345
# Window 2: Send simulated UDP broadcast device search (from port 12345)
echo -e '"ssdp:discover"urn:Belkin:device:**' | nc.traditional -b -u -p 12345 239.255.255.250 1900
To request a device's setup.xml
, using the device's port
from config.json
:
# Send a request for the `setup.xml` of a device from the sample config
curl -v 192.168.27.31:12340/setup.xml
The above commands may seem a little complicated if you're unfamiliar, but they're immensely powerful and indispensable for debugging these tricky network issues. If you're not already familiar with them, learning the basics will serve you well in your IoT endeavors!
To verify that Fauxmo is working properly, check for a few things:
- Is the Pi consistently seeing the Echo's
M-SEARCH
requests? - Is Fauxmo consistently replying with the
LOCATION
responses? - Is the Echo then requesting the
setup.xml
(for each device)? - Is Fauxmo consistently replying with the setup info?
If you can confirm that things seem to be working through number 4, then it would seem that Fauxmo is working properly, and the issue would seem to be elsewhere.
One way to examine exactly what the Echo sends to one of your connected Fauxmo
devices (i.e. one that already works as expected) is to first stop Fauxmo
(to free up the port), then use netcat to listen to that port while you trigger
the command. E.g. for a Fauxmo device configured to use port 12345
, run
nc.traditional -l 12345
and then tell the Echo to "turn on [device name]".
The Echo will notify you that the command failed, obviously, because Fauxmo
isn't running, but you should be able to see exactly what the Echo sent.
These are the requests that the Echo sends to Fauxmo when you ask it to turn a device...
POST /upnp/control/basicevent1 HTTP/1.1
Host: 192.168.27.31:12345
Accept: */*
Content-type: text/xml; charset="utf-8"
SOAPACTION: "urn:Belkin:service:basicevent:1#SetBinaryState"
Content-Length: 299
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1">
<BinaryState>1</BinaryState>
</u:SetBinaryState>
</s:Body>
</s:Envelope>
POST /upnp/control/basicevent1 HTTP/1.1
Host: 192.168.27.31:12345
Accept: */*
Content-type: text/xml; charset="utf-8"
SOAPACTION: "urn:Belkin:service:basicevent:1#SetBinaryState"
Content-Length: 299
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1">
<BinaryState>0</BinaryState>
</u:SetBinaryState>
</s:Body>
</s:Envelope>
Several similar terms can be used instead of On
and Off
, e.g. Open
and
Close
; the response looks identical. This Reddit
post
has a good number more that work. NB: the Dim
commands in the post don't seem
to work (likely incompatible with Wemo devices, so the Echo doesn't even try to
send them).
As of sometime around 20171030, it will also now send a GetBinaryState
action when viewing a device, which can be
problematic for earlier versions
of Fauxmo (prior to v0.4.5).
POST /upnp/control/basicevent1 HTTP/1.1
Host: 192.168.27.31:12345
Accept: */*
Content-type: text/xml; charset="utf-8"
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
Content-Length: 299
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetBinaryState xmlns:u="urn:Belkin:service:basicevent:1">
<BinaryState>1</BinaryState>
</u:GetBinaryState>
</s:Body>
</s:Envelope>
I think I have a good idea what the Fauxmo response should look like, thanks to help from:
- u/romanpet
- https://github.com/go-home-iot/belkin/blob/7b62ec854e9510f4857bb9eceeb8fef3d8b55fb4/device.go
POST /upnp/control/basicevent1 HTTP/1.1
Host: 192.168.27.31:12345
Accept: */*
Content-type: text/xml; charset="utf-8"
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
Content-Length: 299
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetBinaryStateResponse xmlns:u="urn:Belkin:service:basicevent:1">
<BinaryState>0</BinaryState>
</u:GetBinaryStateResponse>
</s:Body>
</s:Envelope>