Jump to content

Welcome to Smart Home Forum by FIBARO

Dear Guest,

 

as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.

 

As a member you can:

  •     Start new topics and reply to others
  •     Follow topics and users to get email updates
  •     Get your own profile page and make new friends
  •     Send personal messages
  •     ... and learn a lot about our system!

 

Regards,

Smart Home Forum by FIBARO Team


  • 0

VD SONOS Remote Not working


Ravaoo

Question

I have VD sonos remote installed but is not working

Version 1.0.0 does notting

Version 1.0.1 gifs the playing number and gives volume level. Butons are not working.

Is there a new version? Is there a other solution.

 

I want to use de VD to control the sonos in scenes (not the interface like the sonos plugin)

- select number or playlist to play (example : Alarm sounds)

- play number

-stop playing

 

Anny sugestions? 

Link to comment
Share on other sites

1 answer to this question

Recommended Posts

  • 0

I Have the same issue, think it is related  to a fibaro update, because it works before.

 

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- SONOS Remote & Text To Speech (TTS)
--
-- Copyright (C) 2014-2015 Jean-Christophe Vermandé
--
-- Version 1.0.1
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- CHANGE LOGS: 
--
-- Version 1.0.1 rc
-- Fix vd creation >  HC2 v4.080
--
-- Version 1.0.0 beta
-- Improvement: Auto configuration
-- Improvement: Multiple VD support
-- Improvement: Low latency when triggering commands.
-- Improvement: Some code enhancement / refactoring.
-- New: TTS now use Voice RSS or ResponsiveVoice API with advanced options (duration, 
-- volume, auto Resume) 
-- New: Play stream with advanced options (duration, volume, auto Resume)
--
-- Version 0.1.0
-- Fix Google TTS with client=t in URI
--
-- Version 0.0.9
-- New: TTS version 2 added with external server support and notable improvement
-- 
-- Version 0.0.8
-- Improvement: Play TSS with auto stop mode (set dr parameter to "auto") now works as expected.
-- Improvement: Play TTS with fidex duration (set dr parameter to "xx" seconds) now works as expected.
-- Patch: Main image is now fixed after pressing a button, thanks to Labomatik & JM13.
-- Patch: Bug with XMl parsing for BrowseDirectChildren.
-- Warning: To operate the radio shortcuts you must choose at least two favorite radios.

-- Version 0.0.7
-- Refresh process run faster and more efficiently.
-- Patch line 892: attempt to index local 'value' (a function value)
-- Patch line 1256: attempt to concatenate a nil value
-- Show plugin current version in debug window on startup
-- Add LED control "On" or "Off" -> Sonos:ledState("On");
-- 
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
local _f = fibaro;

if not Toolkit then Toolkit={
    __header="Toolkit",
    __version="1.0.6",
    __luaBase="5.2.0",
    __copyright="Jean-Christophe Vermandé",
    __licence=[[
    Minified version : Compression ratio 50.90%
    
    Copyright (C) 2013-2015 Jean-Christophe Vermandé

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses></http:>.
]],__frameworkHeader=function(self)self:traceEx("green","-------------------------------------------------------------------------")self:traceEx("green","-- HC2 Toolkit Framework version %s",self.__version)self:traceEx("green","-- Current interpreter version is %s",self.getInterpreterVersion())self:traceEx("green","-- Total memory in use by Lua: %.2f Kbytes",self.getCurrentMemoryUsed())self:traceEx("green","-------------------------------------------------------------------------")end,chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",hex="0123456789abcdef",now=os.date,toUnixTimestamp=function(a)return os.time(a)end,fromUnixTimestamp=function(b)return os.date("%c",ts)end,currentTime=function()return tonumber(os.date("%H%M%S"))end,comparableTime=function(d,e,f)return tonumber(string.format("%02d%02d%02d",d,e,f))end,isTraceEnabled=true,isAutostartTrigger=function()local a=fibaro:getSourceTrigger()return a["type"]=="autostart"end,isOtherTrigger=function()local a=fibaro:getSourceTrigger()return a["type"]=="other"end,raiseError=function(g,h)error(g,h)end,colorSetToRgbw=function(self,j)self.assertArg("colorSet",j,"string")local a,i={},1;for k in string.gmatch(j,"(%d+)")do a=k;i=i+1 end;return a[1],a[2],a[3],a[4]end,isValidJson=function(self,l,m)self.assertArg("data",l,"string")self.assertArg("raise",m,"boolean")if string.len(l)>0 then if pcall(function()return json.decode(l)end)then return true else if m then self.raiseError("invalid json",2)end end end;return false end,assertArg=function(name,value,n)if type(value)~=n then Tk.raiseError("argument "..name.." must be "..n,2)end end,trace=function(self,value,...)if self.isTraceEnabled then if value~=nil then return fibaro:debug(string.format(value,...))end end end,traceEx=function(self,o,value,...)self:trace(string.format('<%s style="color:%s;">%s</%s>',"span",o,string.format(value,...),"span"))end,getInterpreterVersion=function()return _VERSION end,getCurrentMemoryUsed=function()return collectgarbage("count")end,trim=function(b)Tk.assertArg("value",b,"string")return string.gsub(b,"^%s*(.-)%s*$","%1")end,isNaN=function(p)return p~=p end,filterByPredicate=function(table,q)Tk.assertArg("table",table,"table")Tk.assertArg("predicate",q,"function")local r,s=1,{}for i=1,#table do local k=tableif k~=nil then if q(k)then s[r]=k;r=r+1 end end end;return s,#s end}Toolkit:__frameworkHeader()Tk=Toolkit end;if not Toolkit.Debug then Toolkit.Debug={__header="Toolkit.Debug",__version="1.0.1",__clocks={["fragment"]=os.clock(),["all"]=os.clock()},benchmarkPoint=function(self,name)__clocks[name]=os.clock()end,benchmark=function(self,g,t,name,u)Toolkit.assertArg("message",g,"string")Toolkit.assertArg("template",g,"string")if u~=nil then Toolkit.assertArg("reset",u,type(true))end;Toolkit:traceEx("yellow","Benchmark ["..g.."]: "..string.format(t,os.clock()-self.__clocks[name]))if u==true then self.__clocks[name]=os.clock()end end}Toolkit:traceEx("red",Toolkit.Debug.__header.." loaded in memory...")if Toolkit.Debug then Toolkit.Debug:benchmark(Toolkit.Debug.__header.." lib","elapsed time: %.3f cpu secs\n","fragment",true)end end;if not Toolkit then error("You must add Toolkit",2)end;if not Toolkit.Collections then Toolkit.Collections={}end;if not Toolkit.Collections.Queue then Toolkit.Collections.Queue={__header="Toolkit.Collections.Queue",__version="1.0.0",__base={__first=0,__count=0,toArray=function(self)local v={}for i=1,self:count()do v=selfend;return v end,clear=function(self)for i=1,self:count()do self=nil end;self.__first=0;self.__count=0 end,enqueue=function(self,value)assert(value~=nil)local r=self.__first+1;self.__count=self.__count+1;self.__first=r;self[r]=value;Tk:trace("add at pos %d value with %s type",r,tostring(self[r]))end,dequeue=function(self)local w=self:peek()self[1]=nil;self.__first=self.__first-1;self.__count=self.__count-1;for i=1,self:count()do self=self[i+1]end;return w end,contains=function(self,value)assert(value~=nil)for i=1,self:count()do if self==value then return true end end;return false end,peek=function(self)return self[1]end,count=function(self)return tonumber(self.__count)end,clone=function(self)return self end},new=function()collectgarbage("collect")return Toolkit.Collections.Queue.__base end,version=function()return Toolkit.Collections.Queue.__version end}Toolkit:traceEx("red",Toolkit.Collections.Queue.__header.." loaded in memory...")if Toolkit.Debug then Toolkit.Debug:benchmark(Toolkit.Collections.Queue.__header.." lib","elapsed time: %.3f cpu secs\n","fragment",true)end end;if not Toolkit then error("You must add Toolkit",2)end;if not Toolkit.Net then Toolkit.Net={__header="Toolkit.Net",__version="1.0.3",__cr=string.char(13),__lf=string.char(10),__crLf=string.char(13,10),__host=nil,__port=nil,__trace=function(k,...)if Toolkit.Net.isTraceEnabled then Toolkit:trace(k,...)end end,__writeHeader=function(x,l)assert(tostring(l)or l==nil or l=="","Invalid header found: "..l)local y=tostring(l)x:write(y..Toolkit.Net.__crLf)Toolkit.Net.__trace("%s.%s::request > Add header [%s]",Toolkit.Net.__header,Toolkit.Net.__Http.__header,y)end,__decodeChunks=function(z)resp=""line="0"lenline=0;len=string.len(z)i=1;while i<=len do c=string.sub(z,i,i)if lenline==0 then if c==Toolkit.Net.__lf then lenline=tonumber(line,16)if lenline==null then lenline=0 end;line=0 elseif c==Toolkit.Net.__cr then lenline=0 else line=line..c end else resp=resp..c;lenline=lenline-1 end;i=i+1 end;return resp end,__readHeader=function(l)if l==nil then error("Couldn't find header")end;local A=""local B={}local i,len=1,string.len(l)while i<=len do local z=l:sub(i,i)or""local C=l:sub(i+1,i+1)or""if z..C==Toolkit.Net.__crLf then i=i+1;table.insert(B,A)A=""else A=A..z end;i=i+1 end;return B end,__readSocket=function(x)local D,len=0,1;local A,l="",""while D==0 and len>0 do l,D=x:read()len=string.len(l)A=A..l end;return A,D end,__Http={__header="HttpRequest",__version="1.0.3",__tcpSocket=nil,__timeout=250,__waitBeforeReadMs=25,__isConnected=false,__isChunked=false,__url=nil,__method="GET",__headers={},__body=nil,__authorization=nil,setBasicAuthentication=function(self,E,F)Toolkit.assertArg("username",E,"string")Toolkit.assertArg("password",F,"string")self.__authorization=Toolkit.Crypto.Base64:encode(tostring(E..":"..F))end,setBasicAuthenticationEncoded=function(self,G)Toolkit.assertArg("base64String",G,"string")self.__authorization=G end,setWaitBeforeReadMs=function(self,H)Toolkit.assertArg("ms",H,"integer")self.__waitBeforeReadMs=H;Toolkit.Net.__trace("%s.%s::setWaitBeforeReadMs > set to %d ms",Toolkit.Net.__header,Toolkit.Net.__Http.__header,H)end,getWaitBeforeReadMs=function(self)return self.__waitBeforeReadMs end,setReadTimeout=function(self,H)Toolkit.assertArg("ms",H,"number")self.__timeout=H;Toolkit.Net.__trace("%s.%s::setReadTimeout > Timeout set to %d ms",Toolkit.Net.__header,Toolkit.Net.__Http.__header,H)end,getReadTimeout=function(self)return self.__timeout end,disconnect=function(self)self.__tcpSocket:disconnect()self.__isConnected=false;Toolkit.Net.__trace("%s.%s::disconnect > Connected: %s",Toolkit.Net.__header,Toolkit.Net.__Http.__header,tostring(self.__isConnected))end,request=function(self,I,J,B,K)Toolkit.assertArg("method",I,"string")assert(I=="GET"or I=="POST"or I=="PUT"or I=="DELETE"or I=="SUBSCRIBE")assert(J~=nil or J=="")self.__isChunked=false;self.__tcpSocket:setReadTimeout(self.__timeout)self.__url=J;self.__method=I;self.__headers=B or{}self.__body=K or nil;local v=self.__method.." "..self.__url.." HTTP/1.1"Toolkit.Net.__trace("%s.%s::request > %s with method %s",Toolkit.Net.__header,Toolkit.Net.__Http.__header,self.__url,self.__method)local L=""if Toolkit.Net.__port~=nil then L=":"..tostring(Toolkit.Net.__port)end;local M="Host: "..Toolkit.Net.__host..L;Toolkit.Net.__writeHeader(self.__tcpSocket,v)Toolkit.Net.__writeHeader(self.__tcpSocket,M)for i=1,#self.__headers do Toolkit.Net.__writeHeader(self.__tcpSocket,self.__headers)end;if self.__authorization~=nil then Toolkit.Net.__writeHeader(self.__tcpSocket,"Authorization: Basic "..self.__authorization)end;if self.__body~=nil then Toolkit.Net.__writeHeader(self.__tcpSocket,"Content-Length: "..string.len(self.__body))Toolkit.Net.__trace("%s.%s::request > Body length is %d",Toolkit.Net.__header,Toolkit.Net.__Http.__header,string.len(self.__body))end;self.__tcpSocket:write(Toolkit.Net.__crLf..Toolkit.Net.__crLf)if self.__body~=nil then self.__tcpSocket:write(self.__body)end;fibaro:sleep(self.__waitBeforeReadMs)local N,D=Toolkit.Net.__readSocket(self.__tcpSocket)Toolkit.Net.__trace("%s.%s::receive > Length of result: %d",Toolkit.Net.__header,Toolkit.Net.__Http.__header,string.len(N))local O,P;if string.len(N)>0 then local Q=string.find(N,Toolkit.Net.__crLf..Toolkit.Net.__crLf)local R=string.sub(N,1,Q+2)if string.len(R)then P=string.sub(R,10,13)Toolkit.Net.__trace("%s.%s::receive > Status %s",Toolkit.Net.__header,Toolkit.Net.__Http.__header,P)Toolkit.Net.__trace("%s.%s::receive > Length of headers reponse %d",Toolkit.Net.__header,Toolkit.Net.__Http.__header,string.len(R))__headers=Toolkit.Net.__readHeader(R)for S,k in pairs(__headers)do if string.find(string.lower(k or""),"chunked")then self.__isChunked=true;Toolkit.Net.__trace("%s.%s::receive > Transfer-Encoding: chunked",Toolkit.Net.__header,Toolkit.Net.__Http.__header,string.len(N))end end end;local T=string.sub(N,Q+4)if self.__isChunked then O=Toolkit.Net.__decodeChunks(T)D=0 else O=T;D=0 end end;return O,P,D end,version=function()return Toolkit.Net.__Http.__version end,dispose=function(self)if self.__isConnected then self.__tcpSocket:disconnect()end;self.__tcpSocket=nil;self.__url=nil;self.__headers=nil;self.__body=nil;self.__method=nil;if pcall(function()assert(self.__tcpSocket~=Net.FTcpSocket)end)then Toolkit.Net.__trace("%s.%s::dispose > Successfully disposed",Toolkit.Net.__header,Toolkit.Net.__Http.__header)end;collectgarbage("collect")Toolkit.Net.__trace("%s.%s::dispose > Total memory in use by Lua: %.2f Kbytes",Toolkit.Net.__header,Toolkit.Net.__Http.__header,collectgarbage("count"))end},isTraceEnabled=false,HttpRequest=function(U,V)assert(U~=Toolkit.Net,"Cannot call HttpRequest like that!")assert(U~=nil,"host invalid input")assert(V==nil or tonumber(V),"port invalid input")collectgarbage("collect")Toolkit.Net.__host=U;Toolkit.Net.__port=V;local W=Toolkit.Net.__Http;W.__tcpSocket=Net.FTcpSocket(U,V)W.__isConnected=true;Toolkit.Net.__trace("%s.%s > Total memory in use by Lua: %.2f Kbytes",Toolkit.Net.__header,Toolkit.Net.__Http.__header,collectgarbage("count"))Toolkit.Net.__trace("%s.%s > Create Session on port: %d, host: %s",Toolkit.Net.__header,Toolkit.Net.__Http.__header,V,U)return W end,version=function()return Toolkit.Net.__version end}Toolkit:traceEx("red",Toolkit.Net.__header.." loaded in memory...")if Toolkit.Debug then Toolkit.Debug:benchmark(Toolkit.Net.__header.." lib","elapsed time: %.3f cpu secs\n","fragment",true)end end;if not Toolkit then error("You must add Toolkit",2)end;if not Toolkit.Xml then Toolkit.Xml={__header="Toolkit.Xml",__version="1.0.1",__node=function(name)local node={}node.___value=nil;node.___name=name;node.___children={}node.___props={}function node:value()return self.___value end;function node:setValue(X)self.___value=X end;function node:name()return self.___name end;function node:setName(name)self.___name=name end;function node:childNodes()return self.___children end;function node:addChild(Y)if self[Y:name()]~=nil then if type(self[Y:name()].name)=="function"then local Z={}table.insert(Z,self[Y:name()])self[Y:name()]=Z end;table.insert(self[Y:name()],Y)else self[Y:name()]=Y end;table.insert(self.___children,Y)end;function node:properties()return self.___props end;function node:addProperty(name,value)local _="@"..name;if self[_]~=nil then if type(self[_])=="string"then local Z={}table.insert(Z,self[_])self[_]=Z end;table.insert(self[_],value)else self[_]=value end;table.insert(self.___props,{name=name,value=value})end;return node end,Node=function(self,name)return self.__node(name)end,ToXmlString=function(value)value=string.gsub(value,"&","&".."amp;")value=string.gsub(value,"<","&".."lt;")value=string.gsub(value,">","&".."gt;")value=string.gsub(value,"\"","&".."quot;")value=string.gsub(value,"([^%w%&%;%p%\t% ])",function(c)return string.format("&#x%X;",string.byte(c))end)return value end,FromXmlString=function(value)value=string.gsub(value,"&#x([%x]+)%;",function(M)return string.char(tonumber(M,16))end)value=string.gsub(value,"&#([0-9]+)%;",function(M)return string.char(tonumber(M,10))end)value=string.gsub(value,"&".."quot;","\"")value=string.gsub(value,"&".."apos;","'")value=string.gsub(value,"&".."gt;",">")value=string.gsub(value,"&".."lt;","<")value=string.gsub(value,"&".."amp;","&")return value end,ParseArgs=function(node,b)string.gsub(b,"(%w+)=([\"'])(.-)%2",function(a0,a1,z)node:addProperty(a0,Toolkit.Xml.FromXmlString(z))end)end,ParseXmlText=function(self,a2)local a3={}local a4=Toolkit.Xml:Node()table.insert(a3,a4)local a5,c,a6,a7,a8;local i,a9=1,1;while true do a5,a9,c,a6,a7,a8=string.find(a2,"<(%/?)([%w_:]+)(.-)(%/?)>",i)if not a5 then break end;local aa=string.sub(a2,i,a5-1)if not string.find(aa,"^%s*$")then local ab=(a4:value()or"")..Toolkit.Xml.FromXmlString(aa)a3[#a3]:setValue(ab)end;if a8=="/"then local ac=Toolkit.Xml:Node(a6)Toolkit.Xml.ParseArgs(ac,a7)a4:addChild(ac)elseif c==""then local ac=Toolkit.Xml:Node(a6)Toolkit.Xml.ParseArgs(ac,a7)table.insert(a3,ac)a4=ac else local ad=table.remove(a3)a4=a3[#a3]if#a3<1 then error("XmlParser: nothing to close with "..a6)end;if ad:name()~=a6 then error("XmlParser: trying to close "..ad:name().." with "..a6)end;a4:addChild(ad)end;i=a9+1 end;local aa=string.sub(a2,i)if#a3>1 then error("XmlParser: unclosed "..a3[#a3]:name())end;return a4 end,version=function()return Toolkit.Xml.__version end}Toolkit:traceEx("red",Toolkit.Xml.__header.." loaded in memory...")if Toolkit.Debug then Toolkit.Debug:benchmark(Toolkit.Xml.__header.." lib","elapsed time: %.3f cpu secs\n","fragment",true)end end;if not Toolkit.HttpUtility then Toolkit.HttpUtility={__header="Toolkit.HttpUtility",__version="1.0.0",urlEncode=function(ae)if ae then ae=string.gsub(ae,"\n","\r\n")ae=string.gsub(ae,"([^%w ])",function(c)return string.format("%%%02X",string.byte(c))end)ae=string.gsub(ae," ","+")end;return ae end,urlDecode=function(ae)if ae then ae=string.gsub(ae,"+"," ")ae=string.gsub(ae,"%%(%x%x)",function(M)return string.char(tonumber(M,16))end)ae=string.gsub(ae,"\r\n","\n")end;return ae end}Toolkit:traceEx("red",Toolkit.HttpUtility.__header.." loaded in memory...")if Toolkit.Debug then Toolkit.Debug:benchmark(Toolkit.HttpUtility.__header.." lib","elapsed time: %.3f cpu secs\n","fragment",true)end end

        
if Sonos==nil then Sonos={__header="SONOS Advanced Remote",__version="1.0.0",_commands=Tk.Collections.Queue.new(),_isPlaying=false,_isMuted=false,_debugProcess=true,transportState="",transportStatus="",volume=0,mediaInfo={title=""},eq={loudness=false},zpStatus={zoneName="",localUID="",macAddress=""},zonePlayers={{ip="",uuid="",coordinator=false,group=""}},radioStations={},currentTrack={isRadio=false,isFile=false,absCount=nil,artist=nil,album=nil,creator=nil,duration=nil,originalTrackNumber=nil,relTime=nil,relCount=nil,title=nil,track=nil,uri=nil},refreshTime=6,defaultRefreshTime=12,props={controlURL={ServerContentDirectory="/MediaServer/ContentDirectory/Control",RendererAVTransport="/MediaRenderer/AVTransport/Control",RendererRenderingControl="/MediaRenderer/RenderingControl/Control",RendererConnectionManager="/MediaRenderer/ConnectionManager/Control",RendererQueue="/MediaRenderer/Queue/Control",DeviceProperties="/DeviceProperties/Control"},serviceType={MediaRenderer="urn:schemas-upnp-org:device:MediaRenderer:1",AVTransport="urn:schemas-upnp-org:service:AVTransport:1",RenderingControl="urn:schemas-upnp-org:service:RenderingControl:1",Queue="urn:schemas-sonos-com:service:Queue:1",GroupRenderingControl="urn:schemas-upnp-org:service:GroupRenderingControl:1",ContentDirectory="urn:schemas-upnp-org:service:ContentDirectory:1",DeviceProperties="urn:schemas-upnp-org:service:DeviceProperties:1"},actions={GetTransportInfo="GetTransportInfo",GetPositionInfo="GetPositionInfo",GetMediaInfo="GetMediaInfo",GetVolume="GetVolume",SetVolume="SetVolume",GetMute="GetMute",SetMute="SetMute",SetLoudness="SetLoudness",GetLoudness="GetLoudness",SetAVTransportURI="SetAVTransportURI",Play="Play",Pause="Pause",Stop="Stop",Previous="Previous",Next="Next",Seek="Seek",Browse="Browse",SetLEDState="SetLEDState",GetLEDState="GetLEDState"},transportState={playing="PLAYING",stopped="STOPPED",pausedPlayback="PAUSED_PLAYBACK",transitioning="TRANSITIONING"},transportStatus={ok="OK"}}}Tk:traceEx("green","-------------------------------------------------------------------------")Tk:traceEx("green","-- %s version %s",Sonos.__header,Sonos.__version)Tk:traceEx("green","-------------------------------------------------------------------------")Sonos.browseDirectory=function(self)Tk:trace("Get browseDirectory request")return sendSoapMessage(self.props.controlURL.ServerContentDirectory,self.props.serviceType.ContentDirectory,{name=self.props.actions.Browse,service=self.props.serviceType.ContentDirectory},"<ObjectID>R:0/0</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter ></Filter><StartingIndex>0</StartingIndex><RequestedCount>5</RequestedCount><SortCriteria></SortCriteria>",function(a)local b=decode(tostring(a:match("<Result>(.+)</Result>"))or"")if b~=nil or b~=""then local c=Toolkit.Xml:ParseXmlText(b)local d=c["DIDL"]local e=1;if d~=nil then local f=d["item"]or{}for g,h in ipairs(f)do Tk:trace("key:"..tostring(g))Tk:trace("value type:"..type(h))Tk:trace("children value:"..type(f[g]))if h~=nil then local i,j="",""if h["dc:title"]~=nil then i=h["dc:title"]:value()end;if h["res"]~=nil then rsRe=h["res"]:value()end;self.radioStations[e]={title=i,res=rsRe}Tk:traceEx("yellow","radio station #%d - %s",e,self.radioStations[e].title)e=e+1 end end;DataPersistence:set(tostring(_f:getSelfId()),{radioStations=self.radioStations})else Tk:traceEx("red","DIDL-Lite node not created!")end else Tk:traceEx("red","Radio Stations results not found!")end end)end;Sonos.getTransportState=function(self)Tk:trace("Get transport state request")return sendSoapMessage(self.props.controlURL.RendererAVTransport,self.props.serviceType.AVTransport,{name=self.props.actions.GetTransportInfo,service=self.props.serviceType.AVTransport},"<InstanceID>0</InstanceID>",function(a)self.transportState=a:match("<CurrentTransportState>(.+)</CurrentTransportState>")or""self.transportStatus=a:match("<CurrentTransportStatus>(.+)</CurrentTransportStatus>")or""end)end;Sonos.getCurrentTrack=function(self)Tk:trace("get current track request")return sendSoapMessage(self.props.controlURL.RendererAVTransport,self.props.serviceType.AVTransport,{name=self.props.actions.GetPositionInfo,service=self.props.serviceType.AVTransport},"<InstanceID>0</InstanceID><Channel>Master</Channel>",function(a)self.currentTrack.track=tonumber(a:match("<Track>(.+)</Track>")or 0)self.currentTrack.duration=tostring(a:match("<TrackDuration>(.+)</TrackDuration>")or"")self.currentTrack.relTime=tostring(a:match("<RelTime>(.+)</RelTime>")or"00:00:00")self.currentTrack.relCount=tonumber(a:match("<RelCount>(.+)</RelCount>")or 0)self.currentTrack.absCount=tonumber(a:match("<AbsCount>(.+)</AbsCount>")or 0)self.currentTrack.uri=tostring(a:match("<TrackURI>(.+)</TrackURI>")or"")local k=decode(tostring(a:match("<TrackMetaData>(.+)</TrackMetaData>")))self.currentTrack.title=string.gsub(decode(tostring(k:match("<dc:title>(.+)</dc:title>")or"")),1,22)self.currentTrack.creator=decode(tostring(k:match("<dc:creator>(.+)</dc:creator>")or""))self.currentTrack.artist=decode(tostring(k:match("<r:albumArtist>(.+)</r:albumArtist>")or""))self.currentTrack.album=decode(tostring(k:match("<upnp:album>(.+)</upnp:album>")or""))self.currentTrack.originalTrackNumber=tostring(k:match("<upnp:originalTrackNumber>(.+)</upnp:originalTrackNumber>")or"")if string.find(decode(self.currentTrack.uri or""),"x-rincon-mp3radio:",1,true)~=nil then self.currentTrack.isRadio=true;self.currentTrack.isFile=false;if self:getMediaInfo()then self.currentTrack.title=string.gsub(self.mediaInfo.title,1,25)end elseif string.find(decode(self.currentTrack.uri or""),"x-file-cifs:",1,true)~=nil then self.currentTrack.isRadio=false;self.currentTrack.isFile=true else self.currentTrack.isRadio=false;self.currentTrack.isFile=false end end)end;Sonos.getMediaInfo=function(self)Tk:trace("Get current media info request")return sendSoapMessage(self.props.controlURL.RendererAVTransport,self.props.serviceType.AVTransport,{name=self.props.actions.GetMediaInfo,service=self.props.serviceType.AVTransport},"<InstanceID>0</InstanceID><Channel>Master</Channel>",function(a)local k=decode(tostring(a:match('<CurrentURIMetaData>(.+)</CurrentURIMetaData>')))self.mediaInfo.title=decode(tostring(k:match('<dc:title>(.+)</dc:title>')or''))end)end;Sonos.getZonePlayer=function(self,h,l)local m={}if l~=nil and l=="ip"then for n,o in ipairs(self.zonePlayers)do if o.ip==tostring(h)then m=o;break end end end;return m end;Sonos.getZpStatus=function(self,p)Tk:trace("Get zone player status")p=p or 0;local q=Tk.Net.HttpRequest(_ip,_port)q:setReadTimeout(2000)local a,r,s=q:request("GET","/status/zp",{'Content-Type: text/xml; charset="utf-8"'})q:disconnect()q:dispose()q=nil;if s==0 then if tonumber(r)==200 then self.zpStatus.zoneName=tostring(a:match("<ZoneName>(.+)</ZoneName>"))self.zpStatus.localUID=tostring(a:match("<LocalUID>(.+)</LocalUID>"))self.zpStatus.macAddress=tostring(a:match("<MACAddress>(.+)</MACAddress>"))return true else Tk:trace("status: %s",r)end else Tk:traceEx("red","Communication error code: "..s)if p<10 then Tk:trace("retry #%d",p)_f:sleep(500)return self:getZpStatus(p+1)else Tk:trace("Error: Code returned %s",tostring(errorcode or"n.c"))end end;return false end;Sonos.getSpeakersIP=function(self,p)Tk:trace("Get status topology, look for speakers IP")p=p or 0;local q=Tk.Net.HttpRequest(_ip,_port)q:setReadTimeout(2000)local a,r,s=q:request("GET","/status/topology",{'Content-Type: text/xml; charset="utf-8"'})q:disconnect()q:dispose()q=nil;if s==0 then if tonumber(r)==200 then local t=tostring(a:match("<ZonePlayers>(.+)</ZonePlayers>"))or""if t~=nil or t~=""then local u=Tk.Xml:ParseXmlText(t)for n,v in pairs(u:childNodes())do Tk:trace("Node name: "..v:name())if v:name()=="ZonePlayer"then local w={}w.name=v:value()or"unknown"Tk:traceEx("green","Node value: %s",w.name)local x=v:properties()if x~=nil and#x>0 then for g,y in pairs(x)do if y.name=="group"then w.group=y.value;Tk:trace(y.name.."="..y.value)elseif y.name=="coordinator"then w.coordinator=y.value;Tk:trace(y.name.."="..y.value)elseif y.name=="location"then Tk:trace(y.name.."="..y.value)local z=y.value:match("http://(%d+.%d+.%d+.%d+):1400")w.ip=z;Tk:trace("IP="..z)elseif y.name=="uuid"then w.uuid=y.value;Tk:trace(y.name.."="..y.value)end end;table.insert(self.zonePlayers,w)end end end;return true end else Tk:trace("status: %s",r)end else Tk:traceEx("red","Communication error code: "..s)if p<10 then Tk:trace("retry #%d",p)_f:sleep(500)return self:getSpeakersIP(p+1)else Tk:trace("Error: Code returned %s",tostring(errorcode or"n.c"))end end;return false end;Sonos.getMute=function(self)Tk:trace("Get mute state request")return sendSoapMessage(self.props.controlURL.RendererRenderingControl,self.props.serviceType.RenderingControl,{name=self.props.actions.GetMute,service=self.props.serviceType.RenderingControl},"<InstanceID>0</InstanceID><Channel>Master</Channel>",function(a)local A=tonumber(a:match("<CurrentMute>(.+)</CurrentMute>")or 0)if A==0 then self._isMuted=false elseif A==1 then self._isMuted=true end;Tk:trace("mute: %s",tostring(self._isMuted))end)end;Sonos.getVolume=function(self)Tk:trace("Get volume request")return sendSoapMessage(self.props.controlURL.RendererRenderingControl,self.props.serviceType.AVTransport,{name=self.props.actions.GetVolume,service=self.props.serviceType.RenderingControl},"<InstanceID>0</InstanceID><Channel>Master</Channel>",function(a)self.volume=tonumber(a:match("<CurrentVolume>(.+)</CurrentVolume>")or 0)Tk:trace("volume: %d",self.volume)end)end;Sonos.getLoudness=function(self)Tk:trace("Get loudness request")return sendSoapMessage(self.props.controlURL.RendererRenderingControl,self.props.serviceType.AVTransport,{name=self.props.actions.GetLoudness,service=self.props.serviceType.RenderingControl},"<InstanceID>0</InstanceID><Channel>Master</Channel>",function(a)local B=tonumber(a:match("<CurrentLoudness>(.+)</CurrentLoudness>")or 0)if B==0 then Tk:trace("Loudness is OFF")self.eq.loudness=false elseif B==1 then Tk:trace("Loudness is ON")self.eq.loudness=true else Tk:trace("Loudness N.C")self.eq.loudness=false end end)end;Sonos.eventUrl=function(self,C)return string.format("http://%s:%s/%s",_ip,_port,C)end;Sonos.subscribeToUPnPEvent=function(self,C,p)Tk:trace("Subscribes to UPNP events: %s",C)local D="http://192.168.1.250:81/api/..."Tk.Net.isTraceEnabled=true;local q=Tk.Net.HttpRequest(_ip,_port)q:setReadTimeout(2000)local a,r,s=q:request("SUBSCRIBE",self:eventUrl(C),{'CALLBACK: <'..D..'>','NT: upnp:event','TIMEOUT: Second-60'})q:disconnect()q:dispose()q=nil;if s==0 then if tonumber(r)==200 then Tk:trace("Subscription response ok. status: %s",r)else Tk:trace("status: %s",r)end else Tk:traceEx("red","Communication error code: "..s)if p<10 then Tk:trace("retry #%d",p)_f:sleep(500)return self.subscribeToUPnPEvent(C,p+1)else Tk:trace("Error: Code returned %s",tostring(errorcode or"n.c"))end end end;Tk:traceEx("red",Sonos.__header.." V "..Sonos.__version.." loaded in memory...")if Tk.Debug then Tk.Debug:benchmark(Sonos.__header.." V "..Sonos.__version.." lib","elapsed time: %.3f cpu secs\n","fragment",true)end end;tablelength=function(E)local F=0;for G in pairs(E)do F=F+1 end;return F end;processResponse=function(H,I)if H==nil then return nil end;return H(I)end;sendSoapMessage=function(J,K,L,I,M,N,p)p=p or 0;local q=Tk.Net.HttpRequest(_ip,_port)q:setReadTimeout(2000)local O=[[
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <s:Body>]]..string.format('<u:%s xmlns:u="%s">%s</u:%s>',L.name,L.service,tostring(I or""),L.name)..[[</s:Body>
  </s:Envelope>
  ]]local a,r,s=q:request("POST",J,{'Content-Type: text/xml; charset="utf-8"','SOAPAction: "'..K..'#'..L.name..'"'},O)q:disconnect()q:dispose()q=nil;if s==0 then if tonumber(r)==200 then if M~=nil then processResponse(M,a)end;return true else Tk:trace("status: %s",r)end else Tk:traceEx("red","Communication error code: "..s)if N~=nil and N==true then return true end;if p<10 then Tk:trace("retry #%d action: %s",p,L.name)_f:sleep(1000)return sendSoapMessage(J,K,L,I,M,N,p+1)else Tk:trace("Error: Code returned %s",tostring(errorcode or"n.c"))end end;return false end;encode=function(P)if P~=nil then return P:gsub("&","&".."amp;"):gsub("<","&".."lt;"):gsub(">","&".."gt;"):gsub('"',"&".."quot;"):gsub("'","&".."apos;")end;return""end;decode=function(P)if P~=nil then return P:gsub("&".."#38;",'&'):gsub("&".."#60;",'<'):gsub("&".."#62;",'>'):gsub("&".."#34;",'"'):gsub("&".."#39;","'"):gsub("&".."lt;","<"):gsub("&".."gt;",">"):gsub("&".."quot;",'"'):gsub("&".."apos;","'"):gsub("&".."amp;","&")end;return""end;clockToSeconds=function(Q)if Q==nil then return end;local R=string.len(Q or"")local S=1;local T=0;for E in Q:gmatch("([^:]+)")do if R==7 or R==8 then if S==1 then T=T+E*3600 end;if S==2 then T=T+E*60 end;if S==3 then T=T+E end elseif R==4 or R==5 then if S==1 then T=T+E*60 end;if S==2 then T=T+E end elseif R==1 or R==2 then if S==1 then T=T+E end end;S=S+1 end;return T end;secondsToClock=function(T)local T=tonumber(T)if T==0 then return"0:00:00"else nHours=string.format("%2.f",math.floor(T/3600))nMins=string.format("%02.f",math.floor(T/60-nHours*60))nSecs=string.format("%02.f",math.floor(T-nHours*3600-nMins*60))return nHours..":"..nMins..":"..nSecs end end;refresh=function()Sonos:getMute()Sonos:getVolume()Sonos:getLoudness()if Sonos:getTransportState()then Tk:trace("transport state: %s",Sonos.transportState)if Sonos.transportState=="PLAYING"or Sonos.transportState=="TRANSITIONING"then Sonos._isPlaying=true;Sonos:getCurrentTrack()Sonos.refreshTime=5 else Sonos._isPlaying=false;Sonos.refreshTime=Sonos.defaultRefreshTime;Sonos.currentTrack={absCount=0,artist="",album="",creator="",duration=0,originalTrackNumber="",relTime="00:00:00",relCount=0,title="",track="",uri=""}end;refreshUI()end end;refreshUI=function()_f:call(_selfId,"setProperty","ui.lblPosition.value",Sonos.currentTrack.relTime or"n.c")local U=""if Sonos.currentTrack.isRadio then U=U.."Radio "end;if Sonos.transportState==Sonos.props.transportState.playing then U=U.."Playing"elseif Sonos.transportState==Sonos.props.transportState.pausedPlayback then U=U.."Paused"elseif Sonos.transportState==Sonos.props.transportState.transitioning then U=U.."Transitioning"elseif Sonos.transportState==Sonos.props.transportState.stopped then U=U.."Stopped"end;if Sonos._isMuted==true then U=U.." (mute)"end;local V=""if Sonos.eq.loudness==true then V="Loudness ON"elseif Sonos.eq.loudness==false then V="Loudness OFF"else V="---"end;_f:call(_selfId,"setProperty","ui.lblEq.value",V)_f:call(_selfId,"setProperty","ui.lblState.value",U)_f:call(_selfId,"setProperty","ui.slVolume.value",Sonos.volume or"n.c")local W=""if string.len(Sonos.currentTrack.track)>0 and Sonos.currentTrack.isRadio==false then W=W..Sonos.currentTrack.track.."-"end;if string.len(Sonos.currentTrack.originalTrackNumber)>0 then W=W..string.format("%s - %s",Sonos.currentTrack.originalTrackNumber,Sonos.currentTrack.title)else W=W..string.format("%s",Sonos.currentTrack.title or"n.c")end;_f:call(_selfId,"setProperty","ui.lblTitle.value",W)_f:call(_selfId,"setProperty","ui.lblZone.value",Sonos.zpStatus.zoneName)_f:call(_selfId,"setProperty","ui.lblArtist.value",Sonos.currentTrack.artist or"n.c")_f:call(_selfId,"setProperty","ui.lblAlbum.value",Sonos.currentTrack.album or"n.c")end;if DataPersistence==nil then DataPersistence={root="x_sonos_object"}DataPersistence.load=function(self)local h=_f:getGlobalValue(self.root)if h==nil then return end;if string.len(h)>0 then local X=json.decode(h)if X and type(X)=="table"then return X else Tk:traceEx("red","Unable to process data, check variable")end else Tk:traceEx("red","No data found!")end end;DataPersistence.remove=function(self,Y)local B=self:load()if B[tostring(Y)]then B[tostring(Y)]=nil;_f:setGlobal(self.root,json.encode(B))end end;DataPersistence.set=function(self,Y,X)local B=self:load()if B==nil then return end;if B[tostring(Y)]then for n,o in pairs(X)do B[tostring(Y)][n]=o end else B[tostring(Y)]=X end;_f:setGlobal(self.root,json.encode(B))end;DataPersistence.get=function(self,Y)local B=self:load()if B and type(B)=="table"then for n,o in pairs(B)do if tostring(n)==tostring(Y or"")then return o end end end;return nil end;DataPersistence.reset=function(self)_f:setGlobal(self.root,json.encode({}))end;DataPersistence.isEmptyGlobalVariable=function(Y)local h=_f:getGlobalValue(Y)if h==nil then return true else if h and string.len(tostring(h))==0 then return true else return false end end end;DataPersistence.updateGlobalVariable=function(self,Y,h,Z)Tk:traceEx("green","Operations are in progress, please wait...")_f:setGlobal(Y,h)if Z then _f:sleep(Z)end end;DataPersistence.createGlobalVariable=function(self,Y,h)local _=Net.FHttp('127.0.0.1',11111)local a,r,a0=_:GET("/api/globalVariables")Tk:traceEx("green","status: %s",r)if tonumber(r)==200 and tonumber(a0)==0 then if a~=nil then local json=json.decode(a)for n=1,#json do if string.lower(json[n].name or"")==string.lower(Y or"")then Tk:traceEx("green","%s already exist",tostring(json[n].name))return 0 end end;local a1,a2,a3=_:POST("/api/globalVariables","{\"name\":\""..Y.."\",\"value\":\""..h.."\"}")if(tonumber(a2)==200 or tonumber(a2)==201)and tonumber(a3)==0 then Tk:traceEx("yellow","Global variable %s has been created successfully!",Y)return 1 else Tk:traceEx("red","Status update %s, Error update %s",a2,a3)return 2 end end else Tk:traceEx("red","Error code: "..a0)return 2 end end end;main=function()if _refreshExecTime==nil then _refreshExecTime=tonumber(os.time()-Sonos.refreshTime)end;if _garbageExecTime==nil then _garbageExecTime=tonumber(os.time()-1800)end;if _count==nil then Tk:trace("HC2 start script at "..os.date())if DataPersistence.isEmptyGlobalVariable("x_sonos_object")then local b=DataPersistence:createGlobalVariable("x_sonos_object","{}")if b==2 then Tk:traceEx("red","Please check variable in panel")os.exit()end end;_count=0 else _count=_count+1 end;if _selfId==nil then _selfId=_f:getSelfId()_ip=_f:get(_selfId,"IPAddress")_port=_f:get(_selfId,"TCPPort")_icons={main=_f:get(_selfId,"deviceIcon")}if _ip==nil or _port==nil then Tk:traceEx("red","You must configure IPAddress and TCPPort first")return end;data={zpStatus={zoneName="",localUID="",macAddress=""},zonePlayers={group="",coordinator=false,location="",ip="",uuid=""},radioStations={},tts="",action="",stream=""}Sonos:getSpeakersIP()Sonos:getZpStatus()Sonos:browseDirectory()local a4=Sonos:getZonePlayer(_ip,"ip")data.zonePlayers.group=a4.group or"null"data.zonePlayers.coordinator=a4.coordinator or false;data.zonePlayers.ip=a4.ip or _ip;data.zonePlayers.uuid=a4.uuid or"RINCON_00000000000000000"data.zpStatus.zoneName=Sonos.zpStatus.zoneName or"null"data.zpStatus.localUID=Sonos.zpStatus.localUID or"RINCON_00000000000000000"data.zpStatus.macAddress=Sonos.zpStatus.macAddress or"00:00:00:00:00:00"data.radioStations=Sonos.radioStations;DataPersistence:set(tostring(_f:getSelfId()),data)local X=DataPersistence:load()if X and type(X)=="table"then for n,o in pairs(X)do Tk:traceEx("green","remote ID: "..n)Tk:traceEx("green","zoneName: "..o.zpStatus.zoneName)Tk:traceEx("green","localUID: "..o.zpStatus.localUID)Tk:traceEx("green","macAddress: "..o.zpStatus.macAddress)Tk:traceEx("green","group: "..o.zonePlayers.group)Tk:traceEx("green","coordinator: "..tostring(o.zonePlayers.coordinator))Tk:traceEx("green","ip: "..o.zonePlayers.ip)Tk:traceEx("green","uuid: "..o.zonePlayers.uuid)Tk:traceEx("green","radio stations count: "..#o.radioStations)end end end;local a5=os.difftime(os.time(),_refreshExecTime or 0)if a5>=Sonos.refreshTime then _refreshExecTime=os.time()refresh()end;local a5=os.difftime(os.time(),_garbageExecTime or 0)if a5>=1800 then collectgarbage("collect")_garbageExecTime=os.time()Tk:traceEx("yellow","Collect Garbage at "..os.date())local _=Net.FHttp("127.0.0.1",11111)local a=_:GET("/api/virtualDevices")local a6={}if a~=nil then a6=json.decode(a)end;local X=DataPersistence:load()if X and type(X)=="table"then for n,o in pairs(X)do local a7=false;Tk:traceEx("green","remote ID: "..n)if a6~=nil then for a8,o in pairs(a6)do if tostring(o['id'])==tostring(n)then a7=true end end end;if not a7 then Tk:traceEx("red","Remote ID:"..n.." not found, data persist object purge process")DataPersistence:remove(n)end end end end end;Tk.isTraceEnabled=false;main()

Edited by Jothebone
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...