Last active
December 30, 2016 23:28
-
-
Save tenderlove/feec609014ebe2fdcdd5141be28ebf1c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
# Find WeMo Insight switches and turn them on or off. | |
# | |
# Usage: | |
# | |
# WheeMo::Switch.each do |switch| | |
# p switch.friendly_name | |
# if switch.on? | |
# switch.off! | |
# else | |
# switch.on! | |
# end | |
# end | |
# | |
# License: Public Domain | |
require 'socket' | |
require 'net/http' | |
module WheeMo | |
class Switch < Struct.new :location | |
class << self; include Enumerable; end | |
def self.each | |
UPNP.each("upnp:rootdevice") { |response| | |
usn = response['usn'].split ':' | |
if usn.length == 2 && usn.last =~ /Insight/ | |
yield Switch.new URI.parse response['location'] | |
end | |
} | |
end | |
def friendly_name | |
doc = Net::HTTP.get location | |
/<friendlyName>([^<]*)<\/friendlyName>/.match(doc)[1] | |
end | |
def on?; !off?; end | |
def off? | |
res = do_req make_binary_state_req 'Get', '1' | |
/<BinaryState>([^<]*)<\/BinaryState>/.match(res.body)[1] == '0' | |
end | |
def on! | |
do_req make_binary_state_req 'Set', '1' | |
self | |
end | |
def off! | |
do_req make_binary_state_req 'Set', '0' | |
self | |
end | |
private | |
def do_req req | |
http = Net::HTTP.new location.host, location.port | |
http.request req | |
end | |
def make_binary_state_req get_or_set, state | |
req = Net::HTTP::Post.new '/upnp/control/basicevent1' | |
req['SOAPACTION'] = "\"urn:Belkin:service:basicevent:1##{get_or_set}BinaryState\"" | |
req['Content-Type'] = "text/xml; charset=\"utf-8\"" | |
req.body = <<-eoxml | |
<?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:#{get_or_set}BinaryState xmlns:u="urn:Belkin:service:basicevent:1"> | |
<BinaryState>#{state}</BinaryState> | |
</u:#{get_or_set}BinaryState> | |
</s:Body> | |
</s:Envelope> | |
eoxml | |
req | |
end | |
end | |
class UPNP | |
BROADCAST_ADDR = '239.255.255.250' | |
BROADCAST_PORT = 1900 | |
SEARCH = [ | |
"M-SEARCH * HTTP/1.1", | |
"HOST: #{BROADCAST_ADDR}:#{BROADCAST_PORT}", | |
"MAN: \"ssdp:discover\"", | |
"MX: 5", | |
"ST: ssdp:all", | |
] | |
def self.each type = nil, timeout = 2 | |
sock = UDPSocket.new | |
query = SEARCH | |
query += ["ST: #{type}"] if type | |
sock.send(query.join("\r\n") + "\r\n\r\n", 0, BROADCAST_ADDR, BROADCAST_PORT) | |
buf = Net::BufferedIO.new sock | |
loop do | |
rd, = IO.select [sock], nil, nil, timeout | |
break unless rd | |
yield Net::HTTPResponse.read_new buf | |
end | |
ensure | |
sock.close if sock | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment