This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Check if SONOS queue is empty
#1
Hello, I'm trying to figure out a way to check if the queue on my SONOS is empty or not.
I programmed pushbuttons to control play/pauze and volume up/down. Works fine except when the queue is empty. In that case pushing the programmed play button is of course not starting anything, so it would be a nice feature if I could then just start my Default streaming radio station.
I thought of using the Transportstate ("STOPPED" would mean the queue is empty) but I noticed that the state also shortly goes to "STOPPED" in-between songs which makes it not 100% reliable.

Any suggestions would be kindly appreciated.
Reply
#2
Hi David,

You can get the number of items from the Sonos by using MediaRenderer  -> Queue -> Browse and then invoke with QueueID = 0, StartingIndex = 0, RequestedCount = 0

If you include this in your function upnpavcmd you should be able to get the NumberReturned value that holds the number of items inside the Queue

If NumberReturned = 0 then you can start your Radio URI

See attachment for screenshot from Device Spy with the fields you need

Good luck!

BR,

Erwin

Attached Files Thumbnail(s)
   
Reply
#3
Hi David,

I had some spare time and added it to the function:

Code:
-- Set Sonos IP address
sonos_ipaddress = '192.168.10.31'

-- Function to send commands to Sonos
function upnpavcmd(host, port, cmd, param)
 local client, soap, reqs, service, res, err
 require('socket')
 client = socket.tcp()
 client:settimeout(3)
 -- Try connecting to upnp endpoint
 res, err = client:connect(host, port)
 if not res then
   return nil, err
 end
 -- Guess service name based on command
 if cmd == 'SetVolume' or
 cmd == 'GetVolume' or
 cmd == 'SetMute' or
 cmd == 'GetMute' or
 cmd == 'SetBass' or
 cmd == 'GetBass' or
 cmd == 'SetTreble' or
 cmd == 'GetTreble' or
 cmd == 'SetLoudness' or
 cmd == 'GetLoudness' then
   media = 'MediaRenderer'
   service = 'RenderingControl'
 elseif cmd == 'Browse' then
   media = 'MediaServer'
   service = 'ContentDirectory'
 else
   media = 'MediaRenderer'
   service = 'AVTransport'
 end
 -- Soap envelope
 soap = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' ..
          '<s:Body>' ..
            '<u:' .. cmd .. ' xmlns:u="urn:schemas-upnp-org:service:' .. service .. ':1">' ..
              '<InstanceID>0</InstanceID>' ..
              (param or '') ..
            '</u:' .. cmd .. '>' ..
          '</s:Body>' ..
        '</s:Envelope>'
 -- Http request  
 reqs = 'POST /' .. media .. '/' .. service .. '/Control HTTP/1.1\r\n' ..
        'CONNECTION: close\r\n' ..
        'HOST: ' .. host .. ':' .. port .. '\r\n' ..
        'CONTENT-LENGTH: ' .. soap:len() .. '\r\n' ..
        'CONTENT-TYPE: text/xml; charset="utf-8"\r\n' ..
        'SOAPACTION: "urn:schemas-upnp-org:service:' .. service .. ':1#' .. cmd .. '"\r\n' ..
        '\r\n' .. soap
 -- Send http request
 res, err = client:send(reqs)
 if not res then
   return nil, err
 end
 -- Get reply and close connection
 res, err = client:receive('*a')
 client:close()
 return res, err
end

-- Get what's in the queue
function getQueueContent(ip, port)
BrowseConfig = '<ObjectID>Q:0</ObjectID>' ..
 '<BrowseFlag>BrowseDirectChildren</BrowseFlag>' ..
 '<Filter>*</Filter>' ..
 '<StartingIndex>0</StartingIndex>' ..
 '<RequestedCount>0</RequestedCount>' ..
 '<SortCriteria>*</SortCriteria>'
 result,err = upnpavcmd(ip, port, 'Browse', BrowseConfig)
 return result,err
end

-- Command to get queue content and count (<NumberReturned>)
queuecontent = getQueueContent(sonos_ipaddress, 1400)
for i in string.gmatch(queuecontent, '<NumberReturned.-</NumberReturned>') do
 if i ~= nil then
   queuecount =  i:match([[<NumberReturned>(.-)</NumberReturned>]])
   if queuecount then
     queuecount = tonumber(queuecount)
   end
 end
end

-- Do action(s) based on number of items inside queue
if queuecount > 0 then
 -- Put here your normal play action
else
 -- Put here your URI play action
end

BR,

Erwin van der Zwart
Reply
#4
Hello Erwin, first of all many thanks for looking into my question.
I tried the code you provided but something seems to be going wrong. I may be doing something wrong but I cannot seem to figure out exactly what.
Attached a screenshot of the error log + your code in the background. Apparently is goes wrong at line 74.

Any ideas what the cause of this might be?

Many thanks,
David

Attached Files Thumbnail(s)
   
Reply
#5
Hi David,

I checked, and there was indeed a small issue, but not on line 74. Did you copied the code from chrome? If yes please copy from other browser to avoid Chrome copy issue

Can you try to replace the code @ line 80:

Code:
queuecount =  i:match([[<NumberReturned>(.-)</NumberReturned>]])

with:

Code:
queuecount = string.match(i, '%d+')

BR,

Erwin

Attached Files Thumbnail(s)
   
Reply
#6
Hello Erwin, I copied with Safari. I had experienced problems before but I had no idea that this was related to the browser. I just retyped the lines until there were no reported faults anymore.
Tried it with Firefox now and that seems to work perfect.

Thanks for the tip :-)

With the brand new copy in Firefox and replacing the one line you suggested it works just fine now.

Thanks a lot for your help.

Best regards,
David
Reply


Forum Jump: