Setting up a Belkin WeMo Switch without iOS

February 15th, 2013

Recently, Belkin released the Wemo Switch, a device that essentially allows you to control an electrical outlet via WiFi. Just one problem–it only works with iOS devices. (Belkin announced an Android app at CES, to enter beta on the Galaxy S3 later this month.)

I, being far too impatient to wait for said beta, and curious as to if it could be used without it, I bought one anyway. This is my story.

Before I get any further, I’d like to give a big shoutout to Issac Kelly, who did a good portion of the heavy lifting, and without whom I would probably not be writing this. Thanks!


So, I got home, unboxed the device, and plugged my lamp in it. The LED blinked orange and blue, letting me know it was awaiting setup. Pushing the power button on the device itself switched the lamp on and off, with the satisfying click of a relay. Clearly my ability to put the right peg in the right hole in kindergarten has yet to escape me.

Normal WeMo setup involves connecting your mobile device to the WeMo’s internal IP (SSID WeMo) and launching the app on your phone. From there, the app shows a list of what APs the WeMo can see, you pick one, type the password, and voila, you’re connected. I soon realized this would not be quite so easy.

Problem 1: Windows and Python

I grabbed miranda.py and miranda.py from Issac’s github. Ran miranda.py, and… failed.

C:\Users\Matt\wemo>python wemo.py
Unmet dependency: No module named IN

Well, damn. What’s IN? To Google we go! Turns out, you don’t need it on Windows. Deleted its import, try again.

C:\Users\Matt\wemo>python wemo.py
Unmet dependency: No module named readline

You’re really not going to make this easy, are you? Luckily, as it turns out, there’s a really easy to set up readline package for Python on Windows called pyreadline. At this point, however, I just decided to switch over to my Ubuntu partition for a while. (This proved to be necessary anyway a little later on.)

Problem 2: WeMo and SSDP

So I got Python working (on Linux, anyway), and quickly hit a new roadblock. Opening miranda and entering the command msearch (the command used to automatically search for UPnP devices) found nothing. I’m hypothesizing (but have no real way to prove this) that because the setup process is exactly the same for every WeMo switch (every device has the same IP address, 10.22.22.1, during setup) that the app need not “discover” anything. Clearly I was going to have to find a workaround.

What about pcap mode, in which it listens for UPnP packets and detects hosts that way? Can’t hurt, right? Well, it seemed to find itself. So I saved the host it found to a new file, which I could, hopefully, modify to point to the WeMo. Turns out, I could! (Props to the miranda crew for making it human-readable). So I made a few changes:

(dp0
I0
(dp1
S'xmlFile'
p2
S'http://10.22.22.1:49153/setup.xml'
p3
sS'name'
p4
S'10.22.22.1:49153'
p5
sS'proto'
p6
S'http://'
p7
sS'deviceList'
p8
(dp9
sS'serverType'
p10
NsS'upnpServer'
p11
S'Linux/2.6.21, UPnP/1.0, Portable SDK for UPnP devices/1.6.6'
p12
sS'dataComplete'
p13
I00
ss.

Then reran miranda and loaded the newly updated file. But when it came time to enumerate the commands the WeMo offered, it failed. It seemed it was not listening on port 49153 as was found by Issac. So I ran nmap and it’s got 49152 open. Maybe that’s it. Change lines 6 and 10 to 49152, reload, and, we have connection! Just a quick test:

upnp> host send 0 controllee basicevent SetBinaryState

Required argument:
Argument Name: BinaryState
Data Type: Boolean
Allowed Values: []
Set BinaryState value to: 0

And hooray, I’m in the dark! My computer is talking to the WeMo. But could I get it to connect to my WAP?

Problem 3: WiFi Setup

The WeMo advertises a service called WiFiSetup. Probably a good place to start. First I made sure it could even see the WAP:

upnp> host send 0 controllee WiFiSetup GetApList

ApList : Page:1/1/2$
Cisco30848G|2|100|WPA1PSKWPA2PSK/TKIP,
NETGEAR24|7|24|WPA2PSK/AES,

Well, that’s a good sign at least. However, when I tried to send the ConnectHomeNetwork command, miranda crashed. Time to send SOAP requests at the device manually.

Checking http://10.22.22.2:49152/setupservice.xml, I found that the ConnectHomeNetwork command takes five arguments: ssid, auth, password, encrypt, and channel, all of which but the password are supplied by GetApList. So crafting a SOAP request shouldn’t be hard:

<?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:ConnectHomeNetwork xmlns:u="urn:Belkin:service:WiFiSetup:1">
   <auth>WPA1PSKWPA2PSK</auth>
   <channel>2</channel>
   <encrypt>TKIP</encrypt>
   <password>--redacted--</password>
   <ssid>Cisco30848G</ssid>
  </u:ConnectHomeNetwork>
 </s:Body>
</s:Envelope>

And just shoot it over with curl, right? Easy. Got a message saying it was connecting and everything. But the light’s still blinking blue and orange. Maybe check the router UI?

Pulling up my router’s webpage revealed that it was trying to connect… unsuccessfully. I tried both WPA1 and WPA2 individually as well; neither worked. I didn’t want to disable encryption on the router altogether, so instead, I made a virtual AP in DD-WRT called WeMo to which only my WeMo’s MAC can connect. (Not the best security, I know. I hope to move it to its own VLAN and prevent Internet traffic from routing to it soon, and moving it to the encrypted side as soon as the official method is out.)

So I sent a new SOAP request over:

<?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:ConnectHomeNetwork xmlns:u="urn:Belkin:service:WiFiSetup:1">
   <auth>OPEN</auth>
   <channel>2</channel>
   <encrypt>NONE</encrypt>
   <password></password>
   <ssid>WeMo</ssid>
  </u:ConnectHomeNetwork>
 </s:Body>
</s:Envelope>

And it says it’s connecting. But same blue/orange light. Hmm. Maybe it has something to do with this CloseSetup command?

<?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:CloseSetup xmlns:u="urn:Belkin:service:WiFiSetup:1">
  </u:CloseSetup>
 </s:Body>
</s:Envelope>

Success! The light has stopped blinking! (And my laptop dropped from the WeMo’s internal AP, which has since disappeared.) Reconnecting to my home AP and telling miranda to send on port 49153 and shooting the WeMo some SetBinaryState 0 and SetBinaryState 1 commands successfully flashed the room lights.

Problem 4: WeMo and SSDP, Part Two

So it’s connected to my WAP–maybe now it’ll respond to discovery requests. Sadly, this does not seem to be the case. I’m wondering if my router may be interfering with UPnP in some way. No worries, I can hardcode it. I’ve set my router up to always assign it the same IP address, so telling my scripts to talk to 10.0.0.103 won’t be too hard. (Plus, I’ll avoid waiting for it to discover the device every single time I run a script.)

Problem 5: User Experience

Sadly, I don’t get quite as rich an experience as iOS users; I can’t yet control from my mobile (though it would be trivial to write a small web app where you push a button and it toggles the status of the switch). I did, however, using Issac’s wemo.py write three little Python scripts that will switch the device on, off, or toggle the state of the switch, all of which are pretty similar:

# lampOff.py

from wemo import off

off()

# lampOn.py

from wemo import on

on()

# lampToggle.py

from wemo import on, off, get

if get():
	off()
else:
	on()

After hardcoding the IP into wemo.py, running each of the three scripts gave the expected result. Finally, success was truly mine. I made a taskbar shortcut to flip the lights on and off from my computer, and added a Windows Scheduled Task to turn them on at 6:45 AM on every weekday, in conjunction with my alarm clock.

Conclusion

So, it’s possible to use a WeMo without an iPhone. It took me many hours of trial and error to get it right, but I finally got it. And, now that I’ve done it once, in the future it shouldn’t take me any more than about 10 minutes to get working again. Hopefully this provides you with the tools to do the same. Thanks again to Issac Kelly, without whose work I would not be writing this, and in fact would probably have taken the damn thing back to the store by now.


Update (2/16/13 12:56 AM CST): I’ve received word that Belkin have just released their beta Android app for the Galaxy S3 (which may also work on other ICS devices). So if you’ve got one of those, there’s that.

Tags: , , , ,

38 Responses to “Setting up a Belkin WeMo Switch without iOS”

  1. Tim Montague says:

    Not able to get this working on Ubuntu. If anyone could present a clean step-by-step set of instructions that would be great. On Windows, I can detect the Belkin WeMo switch in the network, but on Ubuntu using “Python wemo.py” the script never detects any devices – and running “./miranda.py” with the “pcap” command, returns another a device on my network – but won’t detect my Belkin WeMo switch…

    Any suggestions?

    • Matt says:

      Under Problem 2 I detail my problems with getting UPnP discovery to work; saving the code in the code highlight block in that section and loading it in miranda (load <filename> followed by host get 0) should get you to a point where you can send commands to the deice.

  2. Howard says:

    Thanks for the article. Yes, it’s totally possible without the iPhone. If you have the Samsung Galaxy S3 or any device running Ice Cream Sandwich you can download the Beta of the WeMo app. For those who are interested go here: http://www.homeautomationist.com/belkin-wemo-android-app-beta/

    • Matt says:

      Yeah, unfortunately I went through all this work shortly before the Android app came out. It still needs some work (for example, it’s unable to perform initial setup on a WeMo device running the latest firmware, which totally sucks when updating said firmware forces you to factory reset the device). Rules are also non-existent, relying instead upon IFTTT to do the heavy lifting. Hopefully they polish it up a bit before the final release.

  3. Tomas K. says:

    Hi Matt,
    could you please provide also SOAP requests for “shooting the WeMo some SetBinaryState 0 and SetBinaryState 1 commands successfully flashed the room lights” also with HTTP headers AND URL sent by your script to Wemo switch. I need to reproduce the same thing via Java, but upnp library (cling) is too rigid on specification and fails parsing the device/service info. I can fix that and will do upnp discovery and xml parsing on my own, but first I need a proof of concept that I will be able to issue correct http (soap) requests to the switch – and to do that I need to learn from working request. I see the device on the network, see all the info from setup.xml and basicevent service, but I am not sure how to “transform it” into target soap request with correct headers on correct URL. Unfortunatelly, I cannot find anything on the web and since you´re already up and runnig – you can really boost me on. Thank you very much in advance.

    • Matt says:

      Sure thing–here’s what the full SOAP request looks like for SetBinaryState 0:

      POST /upnp/control/basicevent1 HTTP/1.1
      SOAPACTION: ”urn:Belkin:service:basicevent:1#SetBinaryState”
      Content-Length: 316
      Content-Type: text/xml; charset=”utf-8″
      HOST: 10.22.22.1:49152
      User-Agent: CyberGarage-HTTP/1.0

      <?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>
      </div>

      Hopefully that helps.

  4. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  5. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  6. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  7. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  8. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  9. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  10. [...] Galisa] decided to test their hands with setting up the actual Belkin WeMo outlet without using the Mobile phone iphone software . The actual equipment is really a pass-through with regard to mains voltage that allows you to [...]

  11. Issac Kelly says:

    Thanks for linking me up! Congrats on getting on Hack a Day.

  12. [...] Galisa] decided to try his hand at setting up the Belkin WeMo outlet without using a Smartphone app. The hardware is a pass-through for mains voltage which allows you to switch the plug over the [...]

  13. Steve A. says:

    I am wondering if you’d be willing to post this Javascript you’d mentioned. I’ve been attempting to re-create it for the purpose of adding the functionality to control the wemo devices I’ve purchased via a web-based interface that I’d written in php to control my Phillips Hue lightbubs.

    I have already used the iOS app to connect the wemo device to my home wifi network and am able to get a response from http://10.10.10.12:49153/setup.xml

    When posting the SOAP request via XMLHttpRequest() (re-using another bit of code I’d found elsewhere on the web) the debugging response I receive is “http://localhost is not allowed by Access-Control-Allow-Origin”.

    Your help is appreciated.

    • Matt says:

      Not sure which JavaScript you’re referring to, but if you’re trying to fire SOAP requests manually you’ll probably want to make sure the UserAgent is set correctly–see below:

      POST /upnp/control/basicevent1 HTTP/1.1
      SOAPACTION: ”urn:Belkin:service:basicevent:1#SetBinaryState”
      Content-Length: 316
      Content-Type: text/xml; charset=”utf-8″
      HOST: 10.22.22.1:49152
      User-Agent: CyberGarage-HTTP/1.0

      <?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>

  14. Steve A. says:

    I have also been working towards getting this functionality built into my website (currently controlling 9 Phillips Hue bulbs).

    From the research I’ve done, Javascript will not post cross-domain (I’m assuming this to mean that it won’t post to another server). This led me to use classic asp/vbscript and a xmlhttp request to post the SOAP packet.

    I’m able to see that the packet is going out (via wireshark), but it seems that it causes the switch to “lock up” and become unresponsive until a power-cycle is performed, which takes forever.

    Anyone else attempting anything along these lines, or have success integrating with a local webserver (I’m using IIS)? If so, I’d be really interested in seeing your code.

    Mine (not working):

    <%
    Dim strSoapReq
    strSoapReq = "1″
    Dim oHttp
    Dim strResult
    Set oHttp = CreateObject(“Microsoft.XMLHTTP”)
    oHttp.open “POST”, “http://10.10.10.13:49153″, false
    oHttp.setRequestHeader “POST /upnp/control/basicevent1 HTTP/1.1″
    oHttp.setRequestHeader “SOAPACTION”, “”"urn:Belkin:service:basicevent:1#SetBinaryState”"”
    oHttp.setRequestHeader “Content-Length”, Len(strSoapReq)
    oHttp.setRequestHeader “Content-Type”, “text/xml; charset=”"utf-8″”"
    oHttp.setRequestHeader “HOST” , “10.10.10.13:49153″
    oHttp.setRequestHeader “User-Agent”, “CyberGarage-HTTP/1.0″
    oHttp.send strSoapReq
    strResult = oHttp.responseText
    response.write(strResult)
    %>

  15. Steve A. says:

    If anyone’s interested in this, got it working via PHP:

    <?php

    $xon = '0′;

    error_reporting(E_ALL);
    ini_set(‘display_errors’, true);
    ini_set(‘display_startup_errors’, true);

    //Change this variables.
    $location_URL = ‘http://10.10.10.13:49153/upnp/control/basicevent1′;
    $action_URL = ‘urn:Belkin:service:basicevent:1#SetBinaryState’;

    $client = new SoapClient(null, array(
    ‘POST’ => ‘/upnp/control/basicevent1 HTTP/1.1′,
    ‘Content-Length’ => strlen($xon),
    ‘Content-Type’ => ‘text/xml; charset=”utf-8″‘,
    ‘HOST’ => ’10.10.10.13:49153′,
    ‘User-Agent’ => ‘CyberGarage-HTTP/1.0′,
    ‘uri’ => ”,
    ‘location’ => $location_URL,
    ));

    try{
    $order_return = $client->__doRequest($xon,$location_URL,$action_URL,1,false);
    //Get response from here
    print_r($order_return);
    }catch (SoapFault $exception){
    var_dump(get_class($exception));
    var_dump($exception);
    }

    ?>

    • Wes says:

      Thank you greatly for getting this with PHP. I’d been fiddling with this for 3 weeks when I finally gave up back in early March. Glad to see someone got it.

      Can’t wait to add it in with the hue lights stuff I have.

      Cheers!

  16. Steve A. says:

    Aaaaand, of course, it stripped the XML again, but… You get the drift.

  17. Steve A. says:

    Wondering if anyone has any information regarding polling the motion sensor for its state? Have ordered one online, but haven’t received it yet. Would assume that a similar getBinaryState SOAP request would work. Would ideally prefer to have the motion sensor send an event trigger to the server, but…

    Thoughts?

    • Matt says:

      Not too sure on the sensor, or if it’s possible at all to poll its state–I think the WeMo app may just tie the sensor to an individual switch.

      • Steve A. says:

        Received the sensors yesterday. It’s completely possible to poll their state (within a few seconds of motion detected) using the same getBinaryState request as is used for the switches. That said, it would still be awesome if someone has a suggestion as to how to get the sensor to communicate its state, upon motion, with a computer rather than the iDevice/Android app, IFTTT.com (If This Then That) has a promising approach, however they don’t have an http request “action” as of yet, so no luck there. Ended up writing a javascript that runs minimized on a machine that polls the sensor on a 3 second interval (looped), then sends the command to switch on the light if motion is sensed.

        • Matt says:

          Maybe sniff the traffic across the network and see what goes on when you trip a sensor, then set about listening for that traffic? Sadly I don’t have much use for the sensor myself or I’d give it a shot.

  18. Johnny says:

    Thanks Matt, you did a great job!

    I have one question. At the final stage, both your PC and the WeMo device connect to the local WiFi router and get IP addresses of the same local subnet, and you are able to see and control the WeMo device. However, can we control it when our PC move to another location using WiFi of a different place? The current iOS base WeMo application allows this to happen through some remote access function. Do you have any idea of how does it work, and is it possible to control from PC from outside the range of the home WiFi? Thanks a lot!

    • Matt says:

      Not yet sure how to enable official remote access or IFTTT without the app, but I believe this requires communication with Belkin’s servers. One could set up a small webapp with, say, Python or Perl, to send SOAP requests to toggle the switch state, though.

  19. fun says:

    Useful information. Lucky me I found your site by accident, and I’m surprised why this accident didn’t took place earlier!
    I bookmarked it.

  20. Katie says:

    Did you ever figure out why miranda crashed when you tried the ConnectHomeNetwork command in step 3?

    • Matt says:

      I think it’s just a bug in Miranda. Sadly I’m not the Python master I wish I were, so I’m not even sure where to start on that one.

  21. dodgem says:

    I was able to debug this a by packet sniffing from the phone app. I can POST the XML as you mention (ConnectHomeNetwork, then CloseSetup), and set my Wemo is up and running…however, the password being sent is encrypted, and I’m not sure on the scheme…

    For reference, this is the XML I sent, and the password value is “412south5th”. If anyone can decode the value in the soap body to arrive at that, I’d love to know…

    HomeRouter
    WPA2PSK
    cftcBYqbmOtmj4PBAQ5NYA==
    190b
    TKIPAES
    6

  22. dodgem says:

    I see it didn’t post the XML correctly. Password value is the encyrypted hash, including the 190b on the next line.

  23. Zack says:

    Can you please post the curl command used to set the wifi ?

    I send this:

    curl -0 -A ” -v -X POST -H ‘Accept: ‘ -H ‘Content-type: text/xml; charset=”utf-8″‘ \
    -H “SOAPACTION: \”urn:Belkin:service:WiFiSetup:1#ConnectHomeNetwork\”" \
    –data @setwifi.xml http://10.22.22.1:49152/upnp/control/WifiSetup1

    where setwifi.xml is the one you posted above (no security wifi)

    and I get the error

    s:Client
    UPnPError

    -1
    Invalid Action

    * STATE: PERFORM => DONE handle 0×80057580; line 1533 (connection #0)
    * Closing connection 0
    * The cache now contains 0 members

Leave a Reply