protocol_notes.md

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:

In summary:

  1. User tells Echo to “find connected devices” or clicks corresponding button in webapp
  2. Echo broadcasts “device search” to 239.255.255.250:1900 (UDP)
  3. Fauxmo response includes LOCATION of setup.xml endpoint for each “device” in config (UDP)
  4. Echo requests setup.xml endpoint at above LOCATION (HTTP) for each device
  5. Fauxmo responds with setup information for each device (HTTP)
  6. 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:

  1. Is the Pi consistently seeing the Echo’s M-SEARCH requests?
  2. Is Fauxmo consistently replying with the LOCATION responses?
  3. Is the Echo then requesting the setup.xml (for each device)?
  4. 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.

On and Off Commands

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…

On

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>

Off

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>