class Sonos::Discovery

Constants

DEFAULT_TIMEOUT
MULTICAST_ADDR
MULTICAST_PORT

Attributes

default_ip[R]
first_device_ip[R]
timeout[R]

Public Class Methods

new(timeout = DEFAULT_TIMEOUT, default_ip = nil) click to toggle source
# File lib/sonos/discovery.rb, line 25
def initialize(timeout = DEFAULT_TIMEOUT, default_ip = nil)
  @timeout = timeout
  @default_ip = default_ip
  initialize_socket
end

Public Instance Methods

discover() click to toggle source

Look for Sonos devices on the network and return the first IP address found @return [String] the IP address of the first Sonos device found

# File lib/sonos/discovery.rb, line 33
def discover
  send_discovery_message
  @first_device_ip = listen_for_responses
end
topology() click to toggle source

Find all of the Sonos devices on the network @return [Array] an array of TopologyNode objects

# File lib/sonos/discovery.rb, line 40
def topology
  self.discover unless @first_device_ip
  return [] unless @first_device_ip

  doc = Nokogiri::XML(open("http://#{@first_device_ip}:#{Sonos::PORT}/status/topology"))
  doc.xpath('//ZonePlayers/ZonePlayer').map do |node|
    TopologyNode.new(node)
  end
end

Private Instance Methods

initialize_socket() click to toggle source
# File lib/sonos/discovery.rb, line 73
def initialize_socket
  # Create a socket
  @socket = UDPSocket.open

  # We're going to use IP with the multicast TTL
  @socket.setsockopt(Socket::Option.new(:INET, :IPPROTO_IP, :IP_MULTICAST_TTL, 2.chr))
end
listen_for_responses() click to toggle source
# File lib/sonos/discovery.rb, line 57
def listen_for_responses
  begin
    Timeout::timeout(timeout) do
      loop do
        message, info = @socket.recvfrom(2048)
        # return the IP address
        return info[2]
      end
    end
  rescue Timeout::Error => ex
    puts 'Timed out...'
    puts 'Switching to the default IP' if @default_ip
    return @default_ip
  end
end
search_message() click to toggle source
# File lib/sonos/discovery.rb, line 81
def search_message
 [
    'M-SEARCH * HTTP/1.1',
    "HOST: #{MULTICAST_ADDR}:reservedSSDPport",
    'MAN: ssdp:discover',
    "MX: #{timeout}",
    "ST: urn:schemas-upnp-org:device:ZonePlayer:1"
  ].join("\n")
end
send_discovery_message() click to toggle source
# File lib/sonos/discovery.rb, line 52
def send_discovery_message
  # Request announcements
  @socket.send(search_message, 0, MULTICAST_ADDR, MULTICAST_PORT)
end