@Krikroff Sorry but this time I ask in english Is there a simple command to call the defined playlist?
Eg. by replacing cmd in radio5 button I didn't fine solution on forum, maybe exist ... And I doing it (today night my children with wife going to my parents and I have time). Play by VD of playlist work. I use old (2014) LUA script of @Krikroff (I things). In this time without retrieve of playlist name. Only work by id of playlist, Please if wont test it on yours Sonos systems. My work is not big, the code is by @KrikroffI only do the small adaptation and add command of Sonos for play list. The version is not optimized and very professional because I doing it fast for me. I will use it for button and scene of sauna controller ;-)     -- SONOS Play playlist, v.0.1 ------------------------------------------------------------------------------------------- ---made on source of:----------------------------------------------------------------------- -- SONOS Play stream... -- Copyright © 2014 Jean-Christophe Vermandé ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- ---------------------------------- -- User Settings ---------------------------------- ip = "192.168.1.232" port = 1400 FileVol = 10 PlayUnlimited = "Yes" -- si <> Yes, arrêt après 30s environ --duration = ---------------------------------- -- DO not change bellow this line ---------------------------------- selfId = fibaro:getSelfId(); --ip = fibaro:get(selfId, 'IPAddress'); --port = fibaro:get(selfId, 'TCPPort') or 1400; currentTransportState = ""; lastTransportState = ""; currentVolume = 0; lastVolume = 0; ttsVolumeIsDifferent = false; list_name = "Sonos Playlist n1" --not implemented list_nbr = 1 -- playlist number on jffs system of SONOS, You need test it for find interesting list uid = "RINCON_B8E937B01D4E01400" -- find by http://SONOS_IP:1400/status/upnp urlencode = function(str) if (str) then str = string.gsub (str, "\n", "\r\n"); str = string.gsub (str, "([^%w ])", function (c) return string.format ("%%%02X", string.byte(c)) end); str = string.gsub (str, " ", "+"); end return str; end createRequestBody = function(action, schema, data) return string.format("<u:%s xmlns:u=\"%s\">%s</u:%s>", action, schema, data, action); end reponseCallback = function(fnc, args) if (fnc == nil) then return nil; end return fnc(args); end createSocket = function() -- Check IP and PORT before if (ip == nil or port == nil) then fibaro:debug("You must configure IPAddress and TCPPort first"); return; end local socket; local status, err = pcall(function() socket = Net.FTcpSocket(ip, port); socket:setReadTimeout(1000); end); if (status ~= nil and status ~= true) then fibaro:debug("socket status: " .. tostring(status or '')); end if (err ~= nil) then fibaro:debug("socket err: " .. tostring(err or '')); return; end return socket; end disposeSocket = function(socket) if (socket ~= nil) then socket:disconnect(); socket = nil; return true; end return false; end sendSoapMessage = function(url, service, action, args, callback, retry) local socket = createSocket(); if (socket == nil) then return; end retry = retry or 0 -- prepare data local url = "POST " .. url .. " HTTP/1.1"; --local udn = "X-SONOS-TARGET-UDN: uuid:RINCON_B8E937B01D4E01400" -- udn of my SONOS (not need) local soapaction = "SOAPACTION: \"" .. service .. "#" .. action.name .. "\""; local body = createRequestBody(action.name, action.service, tostring(args or "")); local envelope = "<?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>" .. body .. "</s:Body></s:Envelope>"; local ctl = "Content-Length: " .. string.len(envelope); --local payload = url .. "\r\n" .. ctl .. "\r\n" .. udn .. "\r\n" .. soapaction .. "\r\n" .. "\r\n" .. envelope; -- with UDN local payload = url .. "\r\n" .. ctl .. "\r\n" .. soapaction .. "\r\n" .. "\r\n" .. envelope; -- write data local bytes, errorcode = socket:write(payload); if (errorcode == 0) then local state, errorcode = socket:read(); if (errorcode == 0) then if (string.len(state or "") > 0) then -- callback if (callback ~= nil) then reponseCallback(callback, state); end -- dispose ... disposeSocket(socket); return true; else fibaro:debug("Error: Invalid response. response length: " .. string.len(state or "")); end else if (retry < 5) then fibaro:debug("retry #"..retry.." action: " .. action.name); return sendSoapMessage(url, service, action, args, callback, (retry + 1)); else fibaro:debug("Error: Code returned "..tostring(errorcode or "")); end end elseif (errorcode == 2) then fibaro:debug("Error: You must check your IP and PORT settings."); else if (retry < 5) then fibaro:debug("retry #"..retry.." action: " .. action.name); return sendSoapMessage(url, service, action, args, callback, (retry + 1)); else fibaro:debug("Error: Code returned "..tostring(errorcode or "")); end end -- dispose ... disposeSocket(socket); -- default response return false; end stop = function() return sendSoapMessage( -- control url "/MediaRenderer/AVTransport/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "Stop", service = "urn:schemas-upnp-org:service:AVTransport:1" }, -- soap body data (options) "<InstanceID>0</InstanceID><Speed>1</Speed>", -- callback (options) function(response) fibaro:debug("stop sent"); end); end unMute = function() return sendSoapMessage( -- control url "/MediaRenderer/RenderingControl/Control", -- service type "urn:schemas-upnp-org:service:RenderingControl:1", -- action { name = "SetMute", service = "urn:schemas-upnp-org:service:RenderingControl:1" }, -- soap body data (options) "<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredMute>0</DesiredMute>", -- callback (options) function(response) fibaro:debug("unMute sent"); end); end play = function(duration) return sendSoapMessage( -- control url "/MediaRenderer/AVTransport/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "Play", service = "urn:schemas-upnp-org:service:AVTransport:1" }, -- soap body data (options) "<InstanceID>0</InstanceID><Speed>1</Speed>", -- callback (options) function(response) if (duration ~= nil) then fibaro:debug("play sent for " .. duration .. " seconds"); fibaro:sleep(duration); stop(); else fibaro:debug("play sent"); local n = 0; currentTransportState = "TRANSITIONING"; while (currentTransportState == "TRANSITIONING") do if (n > 10) then break end; getTransportState(); fibaro:debug(currentTransportState); fibaro:sleep(5000); n = n + 1; end local i = 0; currentTransportState = "PLAYING"; while (currentTransportState == "PLAYING") do if (i > 10 and PlayUnlimited ~= "Yes") then break end; getTransportState(); fibaro:debug(currentTransportState); fibaro:sleep(2000); i = i + 1; end fibaro:sleep(1000); stop(); end -- update volume with value before tts if different if (ttsVolumeIsDifferent == true) then setVolume(lastVolume); ttsVolumeIsDifferent = false; end end); end sseek = function() return sendSoapMessage( -- control url "/MediaRenderer/AVTransport/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "Seek", service = "urn:schemas-upnp-org:service:AVTransport:1" }, -- soap body data (options) "<InstanceID>0</InstanceID>,<Unit>TRACK_NR</Unit>,<Target>1</Target>", -- callback (options) function(response) fibaro:debug("Seek"); end); end que = function() return sendSoapMessage( -- control url "/MediaRenderer/AVTransport/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "AddURIToQueue", service = "urn:schemas-upnp-org:service:AVTransport:1" }, -- soap body data (options) "<InstanceID>0</InstanceID>,<EnqueuedURI>file:///jffs/settings/savedqueues.rsq#".. list_nbr.."</EnqueuedURI>,<EnqueuedURIMetaData>&lt;DIDL-Lite xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:upnp=&quot;urn:schemas-upnp-org:metadata-1-0/upnp/&quot; xmlns:r=&quot;urn:schemas-rinconnetworks-com:metadata-1-0/&quot; xmlns=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item id=&quot;SQ:1&quot; parentID=&quot;SQ:&quot; restricted=&quot;true&quot;&gt;&lt;dc:title&gt;".. list_name .."&lt;/dc:title&gt;&lt;upnp:class&gt;object.container.playlistContainer&lt;/upnp:class&gt;&lt;desc id=&quot;cdudn&quot; nameSpace=&quot;urn:schemas-rinconnetworks-com:metadata-1-0/&quot;&gt;RINCON_AssociatedZPUDN&lt;/desc&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</EnqueuedURIMetaData>,<DesiredFirstTrackNumberEnqueued>1</DesiredFirstTrackNumberEnqueued>,<EnqueueAsNext>1</EnqueueAsNext>", -- callback (options) function(response) fibaro:debug("que"); end); end setVolume = function(value) return sendSoapMessage( -- control url "/MediaRenderer/RenderingControl/Control", -- service type "urn:schemas-upnp-org:service:RenderingControl:1", -- action { name = "SetVolume", service = "urn:schemas-upnp-org:service:RenderingControl:1" }, -- soap body data (options) "<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>" .. tostring(value) .. "</DesiredVolume>", -- callback (options) function(response) fibaro:debug("Volume set: " .. value); end); end getVolume = function() fibaro:log("Get volume, please wait..."); return sendSoapMessage( -- control url "/MediaRenderer/RenderingControl/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "GetVolume", service = "urn:schemas-upnp-org:service:RenderingControl:1" }, -- soap body data (options) "<InstanceID>0</InstanceID><Channel>Master</Channel>", -- callback (options) function(response) currentVolume = tonumber(response:match("<CurrentVolume>(.+)</CurrentVolume>") or 0); end); end getTransportState = function() return sendSoapMessage( -- control url "/MediaRenderer/AVTransport/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "GetTransportInfo", service = "urn:schemas-upnp-org:service:AVTransport:1" }, -- soap body data (options) "<InstanceID>0</InstanceID>", -- callback (options) function(response) currentTransportState = response:match("<CurrentTransportState>(.+)</CurrentTransportState>") or ""; end); end playFile= function(volume) return sendSoapMessage( -- control url SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI" "/MediaRenderer/AVTransport/Control", -- service type "urn:schemas-upnp-org:service:AVTransport:1", -- action { name = "SetAVTransportURI", service = "urn:schemas-upnp-org:service:AVTransport:1" }, -- soap body data (options) "<InstanceID>0</InstanceID>,<CurrentURI>x-rincon-queue:"..uid.."#0</CurrentURI>,<CurrentURIMetaData></CurrentURIMetaData>", -- zestawienie playlist -- control url --"/MediaServer/ContentDirectory/Control", -- service type --"urn:schemas-upnp-org:service:ContentDirectory:1", -- action --{ name = "Browse", service = "urn:schemas-upnp-org:service:ContentDirectory:1" }, -- soap body data (options) --"<ObjectID>Q:0</ObjectID>,<BrowseFlag>BrowseDirectChildren</BrowseFlag>,<Filter>dc:title,res,dc:creator,upnp:artist,upnp:album,upnp:albumArtURI</Filter>,<StartingIndex>0</StartingIndex>,<RequestedCount>100</RequestedCount>,<SortCriteria></SortCriteria></u:Browse>", -- callback (options) function(response) -- retrieve current transport state getTransportState(); lastTransportState = currentTransportState; -- unmute before unMute(); -- retrieve volume getVolume(); lastVolume = currentVolume; -- set tts volume if <> with current if (volume ~= nil and volume ~= currentVolume) then setVolume(volume); ttsVolumeIsDifferent = true; end sseek(); play(); end); end -- en paramètres: le fichier, puis le volume... que(); playFile(FileVol);