I'd like to share my efforts to scan the network for Sonos speakers. I think it might be useful to others who set themselves up for a similar task.
The code looks simple and straightforward enough when you look at it now, but it took me about 2 days to figure out how to do it.
The script sends an M-SEARCH request to the multicast IP 239.255.255.250:1900, receive and output its answers and stop searching after a timeout of 10s.
Code: Select all
@APPTITLE "M-SEARCH-Test"
@APPAUTHOR "Michael Rupp"
@VERSION 5,0 ; untestet (I use 9.0), but according to the docs this should work since 5.0
@APPDESCRIPTION "The script sends an M-SEARCH request to the multicast IP 239.255.255.250:1900, receive and output its answers and stop searching after a timeout of 10s."
Global m_discoverTimeout = 10000 ; 10s
Global m_marginLeft = 20
Global m_top = 10
/*
* Sending the M-SEARCH request to the multicast IP.
*/
Function p_Discover()
Local ip$ = "239.255.255.250" ; multicast IP
Local port = 1900 ; multicast port
Local udpServerId = CreateUDPObject(Nil)
; ST:urn:schemas-upnp-org:device:ZonePlayer:1 is to look for Sonos speakers, change it to your needs
Local data$ = [[M-SEARCH * HTTP/1.1
HOST: ]] .. ip$ .. ":" .. port .. [[
ST:upnp:rootdevice
MAN:"ssdp:discover"
MX:1
ST:urn:schemas-upnp-org:device:ZonePlayer:1
]]
SendUDPData(udpServerId, data$, ip$, port)
; after m_discoverTimeout, close the UDP object to stop the search.
SetTimeout(Nil,
Function()
TextOut(m_marginLeft, m_top + 10, "Finished.")
CloseUDPObject(udpServerId)
EndFunction, m_discoverTimeout)
EndFunction
/*
* Receive and handle answers from the multicast IP.
*/
Function p_OnReceiveUDPData(data)
p_PrintTable(data)
Local result$ = ReceiveUDPData(data.id)
DebugPrint(result$)
DebugPrint("-----------------------------------------")
Local locaton$ = p_FindHeaderValue(result$, "LOCATION")
TextOut(m_marginLeft, m_top, locaton$, { ListMode = True })
m_top = m_top + 24
EndFunction
/*
* DebugPrint() for table
*/
Function p_PrintTable(table)
For k, v In Pairs(table)
If GetType(v) = #TABLE
DebugPrint(k, ":")
p_PrintTable(v)
Else
DebugPrint(k, ":", v)
EndIf
Next
DebugPrint("-----------------------------------------")
EndFunction
/*
* Find a value in a multiline string formatted like this:
* KEY1: VALUE1
* KEY2: VALUE2
* ...
*/
Function p_FindHeaderValue(header$, name$, endOfValue$)
Local ret$ = ""
If IsNil(endOfValue$)
endOfValue$ = "\n"
EndIf
name$ = name$ .. ":"
Local start = FindStr(header$, name$, False)
If start > -1
start = start + StrLen(name$)
Local end = FindStr(header$, endOfValue$, False, start)
ret$ = StripStr(MidStr(header$, start, end - start))
EndIf
Return(ret$)
EndFunction
InstallEventHandler({ OnReceiveUDPData = p_OnReceiveUDPData })
SetFont(#SANS, 36)
SetFontColor(#LIME)
SetFontStyle(#ANTIALIAS)
TextOut(m_marginLeft, m_top, "M-SEARCH-Test")
m_top = m_top + 46
SetFont(#SANS, 24)
p_Discover()
Repeat
WaitEvent
Forever
Cheers,
Michael