A Groovy Time with UPnP and WeMo
Universal Plug and Play (UPnP) is a networking technology used to discover devices and services on a network. Chances are, if you have any sort of device on your home network it is probably a device that understands UPnP. UPnP uses HTTP over UDP, SOAP, and XML for performing its various interactions. Finding a device involves sending out a discovery packet (using SSDP) to a multicast address and waiting for responses. Within the response, a device description and interface is defined. From there, an application can use the interfaces provided by the device to configure or control it. Furthermore, devices can subscribe to other devices to be notified when various state changes.
For a gift, I received a Belkin WeMo outlet device. It’s an outlet that you plug into an existing outlet that you control using an app on your smartphone. Through the app you can setup a schedule to turn on your living room lamp every day at 6pm and then turn it off at 10pm for example. There are other options using other websites to configure your WeMo device to turn on your exterior lights when you are a certain distance from your house (based on the GPS on your phone), turn on a light when a WeMo motion detector is tripped, and other wild things.
I like the device, except the schedule does not work for me. No matter what I do it will not follow the schedule. So, I did a little digging to see if I could figure out an alternative way to control this thing. It turns out the WeMo is a UPnP device and has a SOAP API that can be used to control it. That’s easy enough to do using a client that can send XML and some headers, but I wanted to learn a little more about it and hopefully at the end of this investigation I would have a utility that I could use with cron to turn my outlet on and off.
Since my WeMo is already on the network and configured, the first thing I needed to do was send out a discovery packet and listen to responses from the devices on my network.
- 1 – Address and port to send the packet to. This is a special IP address and port reserved for UPnP.
- 3, 5 – Create a multicast socket and bind the local IP address and a port.
- 7 – M-SEARCH – Search method
- 8 – HOST – IP address and port reserved for UPnP.
- 9 – MAN – Defines a namespace.
- 10 – MX – Maximum wait time in seconds the device should respond. The device should reply a random number of seconds between 0 and this number.
- 11, 12 – ST – Search target – Line 11 looks for anything that will respond. Line 12 is specifically for Belkin devices.
- 14 – Send the packet.
- 1-5 – Setup the socket for receiving notifications.
- 8 – Data structure to hold the notification.
- 10 – Receive the notification into the packet.
- 11 – Convert the notification into a String for further processing.
Generally you will receive several notifications from each device on your network. Here are some examples of responses received on my network:
The part we care about is the LOCATION header. Copying and pasting the value of the location header into your web browser will display the description of that particular device. For my WeMo it also displays the services provided. Here is an abridged version of the XML returned from my WeMo:
The XML contains basic information about the device including the various services it provides. An interesting element here is the SCPDURL element (line 14). This has the definition of the various actions that this particular service provides. Replacing /setup.xml in the URL with the value of SCPDURL will give you those actions. Here is an action from the truncated XML from the WeMo that we can use to find out if it is on or off:
Using this information, we can build the XML to make our SOAP call to find out the status of the WeMo. Using Groovy’s HTTPBuilder we can send the XML and get the response back. It should be easy to see where the various elements of the XML and the request headers come from.
The actual XML response looks like this:
Here is the request to turn the device on:
Checking the status now, produces this XML:
Putting all these bits of code together, I now have a basic program that I can use to discover WeMo devices on my network, find out the status of the device, and turn it on or off. It should be fairly straightforward to implement functions for setting up schedules and other things the WeMo can do.
My code can be found here: https://github.com/brendonanderson/wemocontrol