WeMo Hacking

I recently got my hands on a Belkin WeMo and decided to put together a web based version of their control panel. For the unaware, the device is just essentially an outlet you can control via UPnP. "Control" mostly means turning it on and off.

Finding Devices

You can find all the devices currently connected to your network using this library: https://github.com/turboladen/upnp

UPnP::SSDP.search("urn:Belkin:device:controllee:1")

You'll get back a list of Belkin devices and more importantly, their ip address. That's found in the :location attribute.

Services

You can use that :location from above to get all the services available, but we're just going to talk about the one we really care about, basicevent.

It's located at /upnp/control/basicevent1 and has an identifier of urn:Belkin:service:basicevent:1. The identifier becomes relevant when constructing actions.

Actions

Each Service exposes a bunch of actions. Since this is SOAP, an action is basically a method. The two we care about are GetBinaryState and SetBinaryState.

Binary State is how the WeMo describes whether it's on or off. 1 means on and 0 means off — makes sense.

GetBinaryState Is the WeMo on or off?

> POST http://10.0.0.11:49153/upnp/control/basicevent1 HTTP/1.1
> Content-type: text/xml; charset="utf-8"
> SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
<!-- Request body -->
<?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"></u:GetBinaryState>
  </s:Body>
</s:Envelope>

<!-- Response body -->
<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>

SetBinaryState Turning the WeMo on and off

> POST http://10.0.0.11:49153/upnp/control/basicevent1 HTTP/1.1
> Content-type: text/xml; charset="utf-8"
> SOAPACTION: "urn:Belkin:service:basicevent:1#SetBinaryState"
<!-- Request body -->
<?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>

Wrapup

Controlling the device is actually pretty easy once you've discovered the various services, actions and XML formats. The problem is that none of it's documented and there aren't any WSDLs. You just have to play around with the services, inspect the XML you get back, etc.

If you don't want to deal with all of this, you're in luck! I've abstracted most of this into a sort of framework. It's just sitting in a little Sinatra app I wrote to control multiple WeMos. Extending it to use more services is pretty straight-forward.

https://github.com/mnoble/wemo/tree/master/lib