Open ryos opened 10 years ago
FWIW, I am also unable to use Switch.find.
I'm afraid I don't have Wemo switches set up at the moment (I've since moved), so I'm not able to debug the issue at present. You should be able to use the library specifying IP/ports manually however, Wemote::Switch.new(<ip>, <port>)
, and then operate on those instances
Yeah, just looked at it more closely. Looks like you're using nmap to update the arp cache and then trying to find the device with a hard coded mac address which doesn't look like it would work very well for everyone :) I'll dig into it and see if i can find a broadcast method to detect the beasts. Thanks for the reply, and thanks for the gem, been using it daily for several years now using the host address without any problem. But I just moved it to a new location and coulnnd't find its ip address readily so this is how I found myself back here. Anyway, cheers.
Yeah, that's right. "b4:75" if I remember correctly is Belkin's OUI and it did end up picking up my devices way back when I was messing around with it all, but not surprising it's having some issues. If you find a more robust mechanism for detecting the devices, let me know - would love to swap it out!
It seems that belkin's uPnP implementation is broken, but I managed to find my one wemo switch using the following ssdp hack.
#!/usr/bin/env ruby
require 'socket'
require 'logger'
class WemoDiscover
# LOCATION: http://192.168.0.21:49153/setup.xml
LOCATION_RE=/LOCATION:\shttp:\/\/(?<addr>\d+\.\d+\.\d+\.\d+):(?<port>\d+)\/(?<path>.*)/
# Simple Service Discovery Protocol (SSDP)
# https://wiki.wireshark.org/SSDP
# https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol
SSDP_ADDR = "239.255.255.250";
SSDP_PORT = 1900;
SSDP_MX = 10;
# Wemo's uPnP implementation seems to be intentionally broken, security through obscurity?
SSDP_ST = "urn:Belkin:device:controllee:1"
SSDP_BROADCAST_ADDR=Addrinfo.udp(SSDP_ADDR, SSDP_PORT)
SSDP_REQUEST = ""
SSDP_REQUEST << "M-SEARCH * HTTP/1.1\r\n"
SSDP_REQUEST << "HOST: %s:%d\r\n" % [SSDP_ADDR, SSDP_PORT]
SSDP_REQUEST << "MAN: \"ssdp:discover\"\r\n"
SSDP_REQUEST << "MX: %d\r\n" % SSDP_MX
SSDP_REQUEST << "ST: %s\r\n" % SSDP_ST
SSDP_REQUEST << "USER-AGENT: unix/5.1 UPnP/1.1 crash/1.0\r\n\r\n";
@@log = Logger.new(STDOUT)
@@log.level = Logger::INFO
def self.debug(on=true)
@@log.level = on ? Logger::DEBUG : Logger::INFO
end
def self.search(timeout = 5)
addrs = []
Socket.open(:INET, :DGRAM) { |sock|
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, 1)
sock.send(SSDP_REQUEST, 0, SSDP_BROADCAST_ADDR)
while true
ready = IO.select([sock], nil, nil, timeout)
break unless ready
sock.recv_nonblock(1024).split(/\n/).each { |line|
# -- example --
#HTTP/1.1 200 OK
#CACHE-CONTROL: max-age=86400
#DATE: Sun, 12 Mar 2017 13:35:47 GMT
#EXT:
#LOCATION: http://192.168.0.21:49153/setup.xml
#OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01
#01-NLS: 7f9a0c3e-1dd2-11b2-aef9-de6f22c3c5e9
#SERVER: Unspecified, UPnP/1.0, Unspecified
#X-User-Agent: redsonic
#ST: urn:Belkin:device:controllee:1
#USN: uuid:Socket-1_0-221425K0100445::urn:Belkin:device:controllee:1
@@log.debug line
m = line.match(LOCATION_RE)
next if m.nil?
# TODO download and parse data from setup.xml, for now we'll just use the addr from LOCATION:
@@log.debug "Found wemo: #{m[:addr]} on port #{m[:port]} with path #{m[:path]}"
addrs << m[:addr]
}
end
}
rescue Interrupt => e
@@log.info "Caught interrupt"
rescue => e
@@log.error "Caught exception #{e}"
ensure
return addrs
end
end
#WemoDiscover::debug(false)
WemoDiscover::search(2).each { |addr| puts "Found wemo at #{addr}" }
When testing I set the timeout to be quite low, since it's on the socket select for each recv.
Thanks for sharing. Maybe I'm doing something dumb here, but when I go Wemote::Switch.all, it returns empty array. Likewise returns nil when doing Wemote::Switch.find("ryos office")
I am also testing wemo gem, and while that gem is less friendly, it does find my Wemo Switch on the network.
Any tips? I'm not an upnp expert, so not sure where to begin.