Simple dashboard of networked WeMo Switches.
$ git clone https://github.com/pgengler/wemo.git
$ cd wemo
$ bundle install
$ rackup
Then visit localhost:9292 in your browser.
The main thing you'll work with is a Wemo::Switch
object. A Switch
represents a physical WeMo switch on your network. They're identified by
the IP address and port the switch lives at.
switch = Wemo::Switch.new("10.0.0.11:49153")
switch.on? # => true
switch.off? # => false
switch.on!
switch.off!
If you don't know the specific location of WeMos on your network, you
can discover them using Wemo::Radar
. A Radar
is initialized with the
device type you want to find.
radar = Wemo::Radar.new("urn:Belkin:service:basicevent:1")
radar.scan # => [#<Wemo::Switch:0x007f8>, #<Wemo::Switch:0x007f9>]
WeMo Switches have a series of Services they offer. These are SOAP endpoints used to retrieve or manipulate data about the Switch.
We only care about one service, for now, BasicEvent service. This is the one used to turn the switch on and off.
Creating a service, in terms of the code, means subclassing
Wemo::Services::Service
and implementing two methods, service_id
and
control_uri
.
class BasicEvent < Wemo::Services::Service
def service_id
"urn:Belkin:service:basicevent:1"
end
def control_uri
"/upnp/control/basicevent1"
end
end
Each Service implements many actions. The BasicEvent service mentioned
above has two actions that we care about, GetBinaryState
and
SetBinaryState
.
Adding new Actions to the library is similar to adding new Services.
Subclass Wemo::Actions::Action
and implement name
and payload
.
Actions are instantiated with an options hash that payload
can then
use.
class GetBinaryState < Wemo::Actions::Action
def name
"GetBinaryState"
end
def payload
<<-XML
<?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>
XML
end
end
The WeMo will send back an XML payload, Responses will need to parse out any data from that which is relevant.
Services will use the Wemo::Responses::Raw
response by default. It just
collects the response, parses the XML into a Hash and nothing more.
Building new responses is just a matter of implementing a class that takes a string in it's initializer.
class RawResponse
def initialize(response)
@data = Hash.from_xml(response)
end
end
Services and Actions are specific to a type of device. You can explore
them all by looking through the various XML documents exposed by
devices. To get to these documents, comb through
Wemo::Switch#attributes
. Specifically,
attributes["root"]["serviceList"]["service"]
and the accompanying
SCPDURL
attributes. Yea... SOAP is awesome,
isn't it?
wemo = Wemo::Switch.new("10.0.0.11:49153")
wemo.attributes
# => { ...Gigantic list of attributes and crap... }