- Location:
- /trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
/trunk/L_Sonos1.lua
r20 r30 2 2 3 3 local http = require("socket.http") 4 4 5 -- 5 Second timeout 5 6 http.TIMEOUT = 5 … … 12 13 </s:Envelope>]] 13 14 14 UPNP_AVTRANSPORT_SID = 'urn:schemas-upnp-org:service:AVTransport:1' 15 UPNP_RENDERING_CONTROL_SID = 'urn:schemas-upnp-org:service:RenderingControl:1' 16 UPNP_DEVICE_PROPERTIES_SID = 'urn:schemas-upnp-org:service:DeviceProperties:1' 15 UPNP_AVTRANSPORT_SERVICE = 'urn:schemas-upnp-org:service:AVTransport:1' 16 UPNP_RENDERING_CONTROL_SERVICE = 'urn:schemas-upnp-org:service:RenderingControl:1' 17 UPNP_DEVICE_PROPERTIES_SERVICE = 'urn:schemas-upnp-org:service:DeviceProperties:1' 18 19 UPNP_AVTRANSPORT_SID = 'urn:upnp-org:serviceId:AVTransport' 20 UPNP_RENDERING_CONTROL_SID = 'urn:upnp-org:serviceId:RenderingControl' 21 UPNP_DEVICE_PROPERTIES_SID = 'urn:upnp-org:serviceId:DeviceProperties' 22 23 local DIDL_FORMAT=[[<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"> 24 <item id="%s" parentID="%s" restricted="true"> 25 <res protocolInfo="x-file-cifs:*:audio/mpeg:*">%s</res> 26 <r:streamContent>%s</r:streamContent> 27 <upnp:albumArtURI>%s</upnp:albumArtURI> 28 <dc:title>%s</dc:title> 29 <upnp:class>%s</upnp:class> 30 <dc:creator>%s</dc:creator> 31 <upnp:album>%s</upnp:album> 32 <upnp:originalTrackNumber>%s</upnp:originalTrackNumber> 33 <r:albumArtist>%s</r:albumArtist> 34 </item> 35 </DIDL-Lite> 36 ]] 17 37 18 38 local log = print … … 24 44 end 25 45 26 function decode(val)46 local function decode(val) 27 47 return val:gsub("&", "&") 28 48 :gsub("<", "<") 29 49 :gsub(">", ">") 30 50 :gsub(""", '"') 31 end 51 end 52 53 local function encode(val) 54 return val:gsub("&", "&") 55 :gsub("<", "<") 56 :gsub(">", ">") 57 :gsub('"', """) 58 end 59 60 function createDIDL(resURI, creator, album, title, artist, streamContent, albumArtURI, trackNumber, class, id, parentID) 61 return DIDL_FORMAT:format(encode(id or 1), 62 encode(parentID or -1), 63 encode(resURI or ""), 64 encode(streamContent or ""), 65 encode(albumArtURI or ""), 66 encode(title or "No title"), 67 encode(class or "object.item.audioItem.musicTrack"), 68 encode(creator or ""), 69 encode(album or ""), 70 encode(trackNumber or 1), 71 encode(artist or "No artist")) 72 end 32 73 33 74 -- event url, user-agent, callback, nt, TimeOut 34 function UPnP_subscribe(ipAddress, ipPort) 35 75 function UPnP_subscribe(ipAddress, ipPort, serverURL, callbackURL) 36 76 -- 37 77 -- Execute the subscription 38 78 -- 39 79 local status, statusMsg = http.request{ 40 method = "SUBSCRIBE /MediaRenderer/RenderingControl/Event HTTP/1.1", 41 headers = {["HOST"] = ipAddress .. ":" .. ipPort, 42 ["CALLBACK"] = "<http://192.168.1.15/cmh/event>", 43 ["NT"] = "upnp:event",}, 44 } 80 url = serverURL:format(ipAddress, ipPort), 81 method = "SUBSCRIBE", 82 headers = {["HOST"] = string.format("%s:%s", ipAddress, ipPort), 83 ["CALLBACK"] = string.format("<%s>", callbackURL), 84 ["NT"] = "upnp:event"} 85 } 86 45 87 return status 46 88 end … … 58 100 :gsub('"', """) 59 101 end 60 102 61 103 local result = "" 62 104 … … 118 160 -- Handle TIMEOUT 119 161 -- 120 return {}162 return false, statusMsg or "An error occurred during the UPnP call" 121 163 end 122 164 … … 125 167 -- Handle SUCCESS 126 168 -- 127 128 if (data == nil or data == "") then 129 return "" 169 if (data == nil or data == "") then 170 return true, "" 130 171 else 131 172 local pattern = string.format('.*<s:Body><u:%sResponse xmlns:u="urn:(.*)">(.*)</u:%sResponse></s:Body></s:Envelope>.*', action, action) … … 134 175 -- TODO: Handle Non-Scalar results 135 176 -- luup.log("Before gmatch: " .. data) 136 177 local sid, value 137 178 for serviceId, result in data:gmatch(pattern) do 138 179 -- luup.log(serviceId .. " --> " .. result) … … 141 182 142 183 -- commented out and returns a simple string instead. Due to multiple tags (not nested though) 143 -- [[local dataTable = {} 144 -- for tagBegin, value, tagEnd in value:gmatch("<(.*)>(.*)</(.*)>") do 145 -- print(tagBegin .. " -> " .. value .. " <- " .. tagEnd) 146 -- dataTable[tagBegin] = value 147 -- end 148 149 -- return dataTable]] 150 return decode(value) 151 184 -- [[local dataTable = {} 185 -- for tagBegin, value, tagEnd in value:gmatch("<(.*)>(.*)</(.*)>") do 186 -- print(tagBegin .. " -> " .. value .. " <- " .. tagEnd) 187 -- dataTable[tagBegin] = value 188 -- end 189 190 -- return dataTable]] 191 return true, decode(value) 152 192 end 153 193 else -
/trunk/S_Sonos1.xml
r20 r30 14 14 <action> 15 15 <name>SetVolume</name> 16 17 18 19 20 21 22 23 24 16 <argumentList> 17 <argument> 18 <name>NewVolume</name> 19 <direction>in</direction> 20 <relatedStateVariable>ui4</relatedStateVariable> 21 </argument> 22 </argumentList> 23 </action> 24 <action> 25 25 <name>SetFileToPlay</name> 26 27 28 29 30 31 32 33 34 26 <argumentList> 27 <argument> 28 <name>FileToPlay</name> 29 <direction>in</direction> 30 <relatedStateVariable>string</relatedStateVariable> 31 </argument> 32 </argumentList> 33 </action> 34 <action> 35 35 <name>SetURIToPlay</name> 36 <argumentList> 37 <argument> 38 <name>URIToPlay</name> 39 <direction>in</direction> 40 <relatedStateVariable>string</relatedStateVariable> 41 </argument> 42 </argumentList> 43 </action> 36 <argumentList> 37 <argument> 38 <name>URIToPlay</name> 39 <direction>in</direction> 40 <relatedStateVariable>string</relatedStateVariable> 41 </argument> 42 </argumentList> 43 </action> 44 <action> 45 <name>Say</name> 46 <argumentList> 47 <argument> 48 <name>Text</name> 49 <direction>in</direction> 50 <relatedStateVariable>string</relatedStateVariable> 51 </argument> 52 <argument> 53 <name>Language</name> 54 <direction>in</direction> 55 <relatedStateVariable>string</relatedStateVariable> 56 </argument> 57 </argumentList> 58 </action> 44 59 </actionList> 45 60 </scpd> -
/trunk/D_Sonos1.xml
r20 r30 24 24 25 25 <service> 26 <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType> 27 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 28 </service> 29 30 <service> 26 31 <serviceType>urn:micasaverde-com:service:Volume:1</serviceType> 27 32 <serviceId>urn:micasaverde-com:serviceId:Volume1</serviceId> -
/trunk/I_Sonos1.xml
r20 r30 3 3 4 4 <functions> 5 local isMuted = true 5 local url = require("socket.url") 6 7 local MSG_CLASS = "Sonos" 8 6 9 local DEBUG_MODE = true 10 local taskHandle = -1 11 12 local TASK_ERROR = 2 13 local TASK_ERROR_PERM = -2 14 local TASK_SUCCESS = 4 15 local TASK_BUSY = 1 16 17 local PARENT_DEVICE 7 18 8 19 local upnp 9 20 21 local HADEVICE_SID = "urn:micasaverde-com:serviceId:HaDevice1" 22 10 23 local ipPort = 1400 -- Sonos 11 24 local UPNP_AVTRANSPORT_URL = 'http://%s:%s/MediaRenderer/AVTransport/Control' 12 25 local UPNP_RENDERING_CONTROL_URL = 'http://%s:%s/MediaRenderer/RenderingControl/Control' 13 26 local UPNP_DEVICE_PROPERTIES_URL = 'http://%s:%s/DeviceProperties/Control' 14 27 local UPNP_RENDERING_EVENT_URL = 'http://%s:%s/MediaRenderer/RenderingControl/Event' 28 29 -- Derived from: 30 -- http://sonosIP:1400/xml/device_description.xml 31 -- 32 local SONOS_AUDIOINPUT_URL = 'http://%s:%s/AudioIn/Control' 33 local SONOS_AUDIOINPUT_SERVICE = 'urn:schemas-upnp-org:service:AudioIn:1' 34 local SONOS_AUDIOINPUT_SID = 'urn:upnp-org:serviceId:AudioIn' 35 15 36 -- local ipPort = 8888 -- Onkyo Receiver 16 37 -- local UPNP_AVTRANSPORT_URL = 'http://%s:%s/upnp_control_2' … … 18 39 19 40 local function log(stuff, level) 20 luup.log( "Sonos: " .. stuff, (level or 50))41 luup.log(string.format("%s: %s", MSG_CLASS, stuff), (level or 50)) 21 42 end 22 43 23 44 local function debug(stuff) 24 45 if (DEBUG_MODE) then 25 log("debug " .. stuff, 1)46 log("debug " .. stuff, 35) 26 47 end 48 end 49 50 local function task(text, mode) 51 luup.log("task " .. text) 52 if (mode == TASK_ERROR_PERM) then 53 taskHandle = luup.task(text, TASK_ERROR, MSG_CLASS, taskHandle) 54 else 55 taskHandle = luup.task(text, mode, MSG_CLASS, taskHandle) 56 57 -- Clear the previous error, since they're all transient 58 if (mode ~= TASK_SUCCESS) then 59 luup.call_delay("clearTask", 30, "", false) 60 end 61 end 62 end 63 64 -- 65 -- Has to be "non-local" in order for MiOS to call it :( 66 -- 67 function clearTask() 68 task("Clearing...", TASK_SUCCESS) 27 69 end 28 70 29 71 -- Low level xml element extracter. Borrowed from @cedriclocqueneux example. Enhanced to handle xml == nil 30 72 local function extractElement(tag, xml, default) 31 if xml == nil then32 return(default) 33 34 73 if (xml == nil) then 74 return(default) 75 else 76 local pattern = "<"..tag..">(.*)</"..tag..">" 35 77 local result = (string.match(xml, pattern) or default) 36 78 return result 37 end 38 end 39 79 end 80 end 81 82 local function setIfChanged(serviceId, name, value, deviceId) 83 local curValue = luup.variable_get(serviceId, name, deviceId) 84 85 if ((value ~= curValue) or (curValue == nil)) then 86 luup.variable_set(serviceId, name, value, deviceId) 87 return true 88 else 89 return false 90 end 91 end 92 93 function refreshCache() 94 debug("refreshCache: start") 95 local status, tmp 96 local changed = false 97 local ip = luup.devices[PARENT_DEVICE].ip 98 99 -- 100 -- Loop every 15 seconds to refresh the cache 101 -- 102 luup.call_delay("refreshCache", 15) 103 104 -- 105 -- The next section reads various status on the Sonos Zone and populates variables on the device. For use by UI or Mute function, etc. 106 -- Is only executed upon initial load of module for now though 107 -- Get ZoneName 108 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_DEVICE_PROPERTIES_URL, 109 "GetZoneAttributes", upnp.UPNP_DEVICE_PROPERTIES_SERVICE, {CurrentZoneName="", CurrentIcon=""}) 110 111 if (status ~= true) then 112 debug("refreshCache: Device offline? status=" .. tmp) 113 return 114 end 115 116 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "ZoneName", extractElement("CurrentZoneName", tmp, ""), PARENT_DEVICE) 117 or setIfChanged(upnp.UPNP_DEVICE_PROPERTIES_SID, "ZoneName", extractElement("CurrentZoneName", tmp, ""), PARENT_DEVICE) 118 or setIfChanged(upnp.UPNP_DEVICE_PROPERTIES_SID, "Icon", extractElement("CurrentIcon", tmp, ""), PARENT_DEVICE) 119 120 -- GetCurrentTransportState (PLAYING, STOPPED, etc) 121 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_AVTRANSPORT_URL, 122 "GetTransportInfo", upnp.UPNP_AVTRANSPORT_SERVICE, {InstanceID="0", CurrentTransportState="", CurrentTransportStatus="", CurrentSpeed="1"}) 123 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentTransportState", extractElement("CurrentTransportState", tmp, ""), PARENT_DEVICE) 124 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "TransportState", extractElement("CurrentTransportState", tmp, ""), PARENT_DEVICE) 125 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "TransportStatus", extractElement("CurrentTransportStatus", tmp, ""), PARENT_DEVICE) 126 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "TransportPlaySpeed", extractElement("CurrentSpeed", tmp, ""), PARENT_DEVICE) 127 128 -- Get Playmode (NORMAL, REPEAT_ALL, SHUFFLE_NOREPEAT, SHUFFLE) 129 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_AVTRANSPORT_URL, 130 "GetTransportSettings", upnp.UPNP_AVTRANSPORT_SERVICE, {InstanceID="0", PlayMode="", ReqQualityMode=""}) 131 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "PlayMode", extractElement("PlayMode", tmp, ""), PARENT_DEVICE) 132 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentPlayMode", extractElement("PlayMode", tmp, ""), PARENT_DEVICE) 133 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentRecordQualityMode", extractElement("RecQualityMode", tmp, ""), PARENT_DEVICE) 134 135 -- Get Current Transport Actions (a CSV of valid Transport Action/Transitions) 136 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_AVTRANSPORT_URL, 137 "GetCurrentTransportActions", upnp.UPNP_AVTRANSPORT_SERVICE, {InstanceID="0"}) 138 changed = changed or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentTransportActions", extractElement("Actions", tmp, ""), PARENT_DEVICE) 139 140 -- Get Audio Line in settings 141 status, tmp = upnp.UPnP_request(ip, ipPort, SONOS_AUDIOINPUT_URL, 142 "GetAudioInputAttributes", SONOS_AUDIOINPUT_SERVICE, {InstanceID="0"}) 143 changed = changed or setIfChanged(SONOS_AUDIOINPUT_SID, "AudioInputName", extractElement("CurrentName", tmp, ""), PARENT_DEVICE) 144 or setIfChanged(SONOS_AUDIOINPUT_SID, "Icon", extractElement("CurrentIcon", tmp, ""), PARENT_DEVICE) 145 146 -- Get Media Information 147 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_AVTRANSPORT_URL, 148 "GetMediaInfo", upnp.UPNP_AVTRANSPORT_SERVICE, {InstanceID="0"}) 149 changed = changed or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "NumberOfTracks", extractElement("NrTracks", tmp, ""), PARENT_DEVICE) 150 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentMediaDuration", extractElement("MediaDuration", tmp, ""), PARENT_DEVICE) 151 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "AVTransportURI", extractElement("CurrentURI", tmp, ""), PARENT_DEVICE) 152 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "NextAVTransportURI", extractElement("NextURI", tmp, ""), PARENT_DEVICE) 153 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "PlaybackStorageMedium", extractElement("PlayMedium", tmp, ""), PARENT_DEVICE) 154 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "RecordStorageMedium", extractElement("RecordMedium", tmp, ""), PARENT_DEVICE) 155 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "RecordMediumWriteStatus", extractElement("WriteStatus", tmp, ""), PARENT_DEVICE) 156 157 -- Get Current URI - song or radio station etc 158 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_AVTRANSPORT_URL, 159 "GetPositionInfo", upnp.UPNP_AVTRANSPORT_SERVICE, {InstanceID="0", Track="0", TrackMetaData="", TrackURI="", RelTime="", AbsTime="", RelCount="0", AbsCount="0"}) 160 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "TrackURI", extractElement("TrackURI", tmp, ""), PARENT_DEVICE) 161 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentTrack", extractElement("Track", tmp, ""), PARENT_DEVICE) 162 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentTrackDuration", extractElement("TrackDuration", tmp, ""), PARENT_DEVICE) 163 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "CurrentTrackURI", extractElement("TrackURI", tmp, ""), PARENT_DEVICE) 164 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "RelativeTimePosition", extractElement("RelTime", tmp, ""), PARENT_DEVICE) 165 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "AbsoluteTimePosition", extractElement("AbsTime", tmp, ""), PARENT_DEVICE) 166 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "RelativeCounterPosition", extractElement("RelTime", tmp, ""), PARENT_DEVICE) 167 or setIfChanged(upnp.UPNP_AVTRANSPORT_SID, "AbsoluteCounterPosition", extractElement("AbsTime", tmp, ""), PARENT_DEVICE) 168 169 -- Get Mute status 170 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_RENDERING_CONTROL_URL, 171 "GetMute", upnp.UPNP_RENDERING_CONTROL_SERVICE, {InstanceID="0", Channel="Master", CurrentMute=""}) 172 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentMute", extractElement("CurrentMute", tmp, ""), PARENT_DEVICE) 173 or setIfChanged(upnp.UPNP_RENDERING_CONTROL_SID, "Mute", extractElement("CurrentMute", tmp, ""), PARENT_DEVICE) 174 175 -- Get Volume 176 status, tmp = upnp.UPnP_request(ip, ipPort, UPNP_RENDERING_CONTROL_URL, 177 "GetVolume", upnp.UPNP_RENDERING_CONTROL_SERVICE, {InstanceID="0", Channel="Master", CurrentVolume=""}) 178 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentVolume", extractElement("CurrentVolume", tmp, ""), PARENT_DEVICE) 179 or setIfChanged(upnp.UPNP_RENDERING_CONTROL_SID, "Volume", extractElement("CurrentVolume", tmp, ""), PARENT_DEVICE) 180 181 if (changed) then 182 luup.variable_set(HADEVICE_SID, "LastUpdate", os.time(), PARENT_DEVICE) 183 end 184 end 185 186 function deferredStartup() 187 debug("deferredStartup: start") 188 189 local status, tmp 190 191 local ip = luup.devices[PARENT_DEVICE].ip 192 193 -- 194 -- Attempt to subscribe to events 195 -- 196 --ip, port, event url, user-agent, callback, nt, TimeOut 197 -- status = upnp.UPnP_subscribe(ip, ipPort, UPNP_RENDERING_EVENT_URL, "http://192.168.5.209:3480/cmh/event") 198 199 refreshCache() 200 end 201 40 202 function sonosStartup(lul_device) 41 203 if (package.path:find("/etc/cmh-ludl/?.lua;/etc/cmh-lu/?.lua", 1, true) == nil) then … … 44 206 package.loaded.L_Sonos1 = nil 45 207 208 log("#" .. lul_device .. " starting up with id " .. luup.devices[lul_device].id) 209 PARENT_DEVICE = lul_device 46 210 upnp = require("L_Sonos1") 47 211 upnp.initialize(debug) 48 49 -- 50 -- Attempt to subscribe to events 51 -- 52 --ip, port, event url, user-agent, callback, nt, TimeOut 53 -- local l_SubscribeInfo = upnp.UPnP_subscribe(luup.devices[lul_device].ip, ipPort) 54 55 -- 56 -- The next section reads various status on the Sonos Zone and populates variables on the device. For use by UI or Mute function, etc. 57 -- Is only executed upon initial load of module for now though 58 -- Get ZoneName 59 local l_DeviceInfo = upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_DEVICE_PROPERTIES_URL, 60 "GetZoneAttributes", upnp.UPNP_DEVICE_PROPERTIES_SID, 61 {CurrentZoneName="", CurrentIcon=""}) 62 l_CurrentZoneName = extractElement("CurrentZoneName", l_DeviceInfo, "") 63 luup.variable_set("urn:schemas-micasaverde-com:device:avmisc:1", "ZoneName", l_CurrentZoneName, lul_device) 64 65 -- GetCurrentTransportState (PLAYING, STOPPED, etc) 66 local l_GetCurrentTransportState = upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 67 "GetTransportInfo", upnp.UPNP_AVTRANSPORT_SID, 68 {InstanceID="0", CurrentTransportState="", CurrentTransportStatus="", CurrentSpeed = "1"}) 69 l_CurrentTransportState = extractElement("CurrentTransportState", l_GetCurrentTransportState, "") 70 luup.variable_set("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentTransportState", l_CurrentTransportState, lul_device) 71 72 -- Get Playmode (NORMAL, REPEAT_ALL, SHUFFLE_NOREPEAT, SHUFFLE) 73 local l_PlayMode = upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 74 "GetTransportSettings", upnp.UPNP_AVTRANSPORT_SID, 75 {InstanceID="0", PlayMode="", ReqQualityMode=""}) 76 l_PlayMode = extractElement("PlayMode", l_PlayMode, "") 77 luup.variable_set("urn:schemas-micasaverde-com:device:avmisc:1", "PlayMode", l_PlayMode, lul_device) 78 79 -- Get Current URI - song or radio station etc 80 local l_PositionInfo = upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 81 "GetPositionInfo", upnp.UPNP_AVTRANSPORT_SID, 82 {InstanceID="0", Track="0", TrackMetaData="", TrackURI = "", RelTime = "", AbsTime = "", RelCount = "0", AbsCount = "0"}) 83 l_TrackURI = extractElement("TrackURI", l_PositionInfo, "") 84 luup.variable_set("urn:schemas-micasaverde-com:device:avmisc:1", "TrackURI", l_TrackURI, lul_device) 85 86 -- Get Mute status 87 local l_CurrentMute = upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 88 "GetMute", upnp.UPNP_RENDERING_CONTROL_SID, 89 {InstanceID="0", Channel="Master", CurrentMute=""}) 90 l_CurrentMute = extractElement("CurrentMute", l_CurrentMute, "") 91 luup.variable_set("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentMute", l_CurrentMute, lul_device) 92 isMuted = l_CurrentMute 93 94 -- Get Volume 95 local l_CurrentVolume = upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 96 "GetVolume", upnp.UPNP_RENDERING_CONTROL_SID, 97 {InstanceID="0", Channel="Master", CurrentVolume=""}) 98 l_CurrentVolume = extractElement("CurrentVolume", l_CurrentVolume, "") 99 luup.variable_set("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentVolume", l_CurrentVolume, lul_device) 100 101 end 102 212 213 luup.call_delay("deferredStartup", 1) 214 end 103 215 </functions> 104 216 <startup>sonosStartup</startup> … … 109 221 <run> 110 222 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 111 "Play", upnp.UPNP_AVTRANSPORT_SID, 112 {InstanceID="0", Speed="1"}) 223 "Play", upnp.UPNP_AVTRANSPORT_SERVICE, 224 {InstanceID="0", Speed="1"}) 225 </run> 226 </action> 227 228 <action> 229 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 230 <name>Play</name> 231 <run> 232 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 233 "Play", upnp.UPNP_AVTRANSPORT_SERVICE, 234 {InstanceID=(lul_settings.InstanceID or "0"), Speed=(lul_settings.Speed or "1")}) 235 </run> 236 </action> 237 238 <action> 239 <serviceId>urn:micasaverde-com:serviceId:Sonos1</serviceId> 240 <name>Say</name> 241 <run> 242 local url = string.format("x-rincon-mp3radio://translate.google.com/translate_tts?tl=%s&q=%s", 243 (lul_settings.Language or "en"), 244 (url.escape(lul_settings.Text or "Please pass a text parameter"))), 245 246 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 247 "SetPlayMode", upnp.UPNP_AVTRANSPORT_SERVICE, 248 {InstanceID=(lul_settings.InstanceID or "0"), NewPlayMode="SHUFFLE_NOREPEAT"}) 249 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 250 "StartAutoplay", upnp.UPNP_AVTRANSPORT_SERVICE, 251 {InstanceID=(lul_settings.InstanceID or '0'), 252 ProgramURI=url, 253 ProgramMetaData="", 254 Volume=(lul_settings.Volume or 50), 255 IncludeLinkedZones=1, 256 ResetVolumeAfter=1}) 257 </run> 258 </action> 259 260 <action> 261 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 262 <name>Record</name> 263 <run> 264 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 265 "Record", upnp.UPNP_AVTRANSPORT_SERVICE, 266 {InstanceID=(lul_settings.InstanceID or "0")}) 267 </run> 268 </action> 269 270 <action> 271 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 272 <name>Seek</name> 273 <run> 274 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 275 "Record", upnp.UPNP_AVTRANSPORT_SERVICE, 276 {InstanceID=(lul_settings.InstanceID or "0"), Unit=(lul_settings.Unit or ""), Target=(lul_settings.Target or "")}) 113 277 </run> 114 278 </action> … … 119 283 <run> 120 284 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 121 "Pause", upnp.UPNP_AVTRANSPORT_SID, 122 {InstanceID="0"}) 123 </run> 124 </action> 285 "Pause", upnp.UPNP_AVTRANSPORT_SERVICE, 286 {InstanceID="0"}) 287 </run> 288 </action> 289 290 <action> 291 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 292 <name>Pause</name> 293 <run> 294 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 295 "Pause", upnp.UPNP_AVTRANSPORT_SERVICE, 296 {InstanceID=(lul_settings.InstanceID or "0")}) 297 </run> 298 </action> 299 125 300 126 301 <action> … … 129 304 <run> 130 305 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 131 "Stop", upnp.UPNP_AVTRANSPORT_SID, 132 {InstanceID="0"}) 306 "Stop", upnp.UPNP_AVTRANSPORT_SERVICE, 307 {InstanceID="0"}) 308 </run> 309 </action> 310 311 <action> 312 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 313 <name>Stop</name> 314 <run> 315 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 316 "Stop", upnp.UPNP_AVTRANSPORT_SERVICE, 317 {InstanceID=(lul_settings.InstanceID or "0")}) 133 318 </run> 134 319 </action> … … 139 324 <run> 140 325 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 141 "Next", upnp.UPNP_AVTRANSPORT_SID, 142 {InstanceID="0"}) 143 326 "Next", upnp.UPNP_AVTRANSPORT_SERVICE, 327 {InstanceID="0"}) 328 </run> 329 </action> 330 331 <action> 332 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 333 <name>Next</name> 334 <run> 335 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 336 "Next", upnp.UPNP_AVTRANSPORT_SERVICE, 337 {InstanceID=(lul_settings.InstanceID or "0")}) 338 </run> 339 </action> 340 341 <action> 342 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 343 <name>NextSection</name> 344 <run> 345 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 346 "NextSection", upnp.UPNP_AVTRANSPORT_SERVICE, 347 {InstanceID=(lul_settings.InstanceID or "0")}) 144 348 </run> 145 349 </action> … … 150 354 <run> 151 355 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 152 "Previous", upnp.UPNP_AVTRANSPORT_SID, 153 {InstanceID="0"}) 154 356 "Previous", upnp.UPNP_AVTRANSPORT_SERVICE, 357 {InstanceID="0"}) 358 </run> 359 </action> 360 361 <action> 362 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 363 <name>Previous</name> 364 <run> 365 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 366 "Previous", upnp.UPNP_AVTRANSPORT_SERVICE, 367 {InstanceID=(lul_settings.InstanceID or "0")}) 368 </run> 369 </action> 370 371 <action> 372 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 373 <name>PreviousSection</name> 374 <run> 375 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 376 "PreviousSection", upnp.UPNP_AVTRANSPORT_SERVICE, 377 {InstanceID=(lul_settings.InstanceID or "0")}) 378 </run> 379 </action> 380 381 <action> 382 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 383 <name>SetPlayMode</name> 384 <run> 385 -- NORMAL, SHUFFLE, SHUFFLE_NOREPEAT, REPEAT_ONE, REPEAT_ALL, RANDOM, DIRECT_1, INTRO 386 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 387 "SetPlayMode", upnp.UPNP_AVTRANSPORT_SERVICE, 388 {InstanceID=(lul_settings.InstanceID or "0"), NewPlayMode=(lul_settings.NewPlayMode)}) 389 </run> 390 </action> 391 392 <action> 393 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 394 <name>SetRecordQualityMode</name> 395 <run> 396 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 397 "SetRecordQualityMode", upnp.UPNP_AVTRANSPORT_SERVICE, 398 {InstanceID=(lul_settings.InstanceID or "0"), NewRecordQualityMode=(lul_settings.NewRecordQualityMode)}) 399 </run> 400 </action> 401 402 <action> 403 <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId> 404 <name>SetMute</name> 405 <run> 406 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 407 "SetMute", upnp.UPNP_RENDERING_CONTROL_SERVICE, 408 {InstanceID=(lul_settings.InstanceID or "0"), Channel=(lul_settings.Channel or "Master"), DesiredMute=(tonumber(lul_settings.DesiredMute) or 1)}) 155 409 </run> 156 410 </action> … … 161 415 <run> 162 416 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 163 "SetMute", upnp.UPNP_RENDERING_CONTROL_SID,164 417 "SetMute", upnp.UPNP_RENDERING_CONTROL_SERVICE, 418 {InstanceID="0", Channel="Master", DesiredMute=1}) 165 419 </run> 166 420 </action> … … 169 423 <serviceId>urn:micasaverde-com:serviceId:Sonos1</serviceId> 170 424 <name>UnMute</name> 171 <run> 172 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 173 "SetMute", upnp.UPNP_RENDERING_CONTROL_SID, 174 {InstanceID="0", Channel="Master", DesiredMute=0}) 175 </run> 176 </action> 177 178 <action> 425 <run> 426 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 427 "SetMute", upnp.UPNP_RENDERING_CONTROL_SERVICE, 428 {InstanceID="0", Channel="Master", DesiredMute=0}) 429 </run> 430 </action> 431 432 <action> 433 <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId> 434 <name>SetVolume</name> 435 <run> 436 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 437 "SetVolume", upnp.UPNP_RENDERING_CONTROL_SERVICE, 438 {InstanceID=(lul_settings.InstanceID or '0'), Channel=(lul.settings.Channel or 'Master'), DesiredVolume=(tonumber(lul_settings.DesiredVolume) or 0)}) 439 </run> 440 </action> 441 442 <action> 179 443 <serviceId>urn:micasaverde-com:serviceId:Sonos1</serviceId> 180 444 <name>SetVolume</name> 181 445 <run> 182 183 "SetVolume", upnp.UPNP_RENDERING_CONTROL_SID,184 446 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 447 "SetVolume", upnp.UPNP_RENDERING_CONTROL_SERVICE, 448 {InstanceID='0', Channel='Master', DesiredVolume=tonumber(lul_settings.NewVolume)}) 185 449 </run> 186 450 </action> … … 190 454 <name>SetFileToPlay</name> 191 455 <run> 192 -- kept for backward compatability to first version. SetURIToPlay should be used instead. Will only allow protocol for files. 193 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 194 "SetAVTransportURI", upnp.UPNP_AVTRANSPORT_SID, 195 {InstanceID='0', CurrentURI="x-file-cifs:" .. lul_settings.FileToPlay, CurrentURIMetaData = ""}) 456 -- kept for backward compatability to first version. SetURIToPlay should be used instead. Will only allow protocol for files. 457 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 458 "SetAVTransportURI", upnp.UPNP_AVTRANSPORT_SERVICE, 459 {InstanceID='0', CurrentURI="x-file-cifs:" .. lul_settings.FileToPlay, CurrentURIMetaData = ""}) 460 </run> 461 </action> 462 463 <action> 464 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 465 <name>SetAVTransportURI</name> 466 <run> 467 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 468 "SetAVTransportURI", upnp.UPNP_AVTRANSPORT_SERVICE, 469 {InstanceID=(lul_settings.InstanceID or '0'), CurrentURI=(lul_settings.CurrentURI), CurrentURIMetaData=(lul_settings.CurrentURIMetaData or "")}) 470 </run> 471 </action> 472 473 <action> 474 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 475 <name>AddURIToQueue</name> 476 <run> 477 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 478 "SetAVTransportURI", upnp.UPNP_AVTRANSPORT_SERVICE, 479 {InstanceID=(lul_settings.InstanceID or '0'), 480 EnqueuedURI=(lul_settings.EnqueuedURI or ""), 481 EnqueuedURIMetaData=(lul_settings.EnqueuedURIMetaData or ""), 482 DesiredFirstTrackNumberEnqueued=(lul_settings.DesiredFirstTrackNumberEnqueued or 1), 483 EnqueueAsNext=(lul_settings.EnqueueAsNext or true)}) 484 </run> 485 </action> 486 487 <action> 488 <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId> 489 <name>RemoveAllTracksFromQueue</name> 490 <run> 491 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 492 "RemoveAllTracksFromQueue", upnp.UPNP_AVTRANSPORT_SERVICE, 493 {InstanceID=(lul_settings.InstanceID or '0'))}) 196 494 </run> 197 495 </action> … … 201 499 <name>SetURIToPlay</name> 202 500 <run> 203 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 204 "SetAVTransportURI", upnp.UPNP_AVTRANSPORT_SID, 205 {InstanceID='0', CurrentURI=lul_settings.URIToPlay, CurrentURIMetaData = ""}) 206 207 -- URI must include protocol as prefix. 208 -- x-file-cifs: 209 -- file: 210 -- x-rincon: 211 -- x-rincon-mp3radio: 212 -- x-rincon-playlist: 213 -- x-rincon-queue: 214 -- x-rincon-stream: 215 -- example is DR Jazz Radio: x-rincon-mp3radio://live-icy.gss.dr.dk:8000/Channel22_HQ.mp3 216 217 </run> 218 </action> 219 501 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_AVTRANSPORT_URL, 502 "SetAVTransportURI", upnp.UPNP_AVTRANSPORT_SERVICE, 503 {InstanceID='0', CurrentURI=lul_settings.URIToPlay, CurrentURIMetaData = ""}) 504 505 -- URI must include protocol as prefix. 506 -- x-file-cifs: 507 -- file: 508 -- x-rincon: 509 -- x-rincon-mp3radio: 510 -- x-rincon-playlist: 511 -- x-rincon-queue: 512 -- x-rincon-stream: 513 -- example is DR Jazz Radio: x-rincon-mp3radio://live-icy.gss.dr.dk:8000/Channel22_HQ.mp3 514 </run> 515 </action> 516 220 517 <action> 221 518 <serviceId>urn:micasaverde-com:serviceId:Volume1</serviceId> … … 223 520 <run> 224 521 -- Toggle Mute 225 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 226 "SetMute", upnp.UPNP_RENDERING_CONTROL_SID, 227 {InstanceID="0", Channel="Master", DesiredMute=isMuted}) 228 229 isMuted = (isMuted == false) 522 local changed = false 523 local isMuted = luup.variable_get(upnp.UPNP_RENDERING_CONTROL_SID, "CurrentMute", lul_device) 524 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 525 "SetMute", upnp.UPNP_RENDERING_CONTROL_SID, {InstanceID="0", Channel="Master", DesiredMute=isMuted}) 526 527 changed = changed or setIfChanged("urn:schemas-micasaverde-com:device:avmisc:1", "CurrentMute", (1-isMuted), lul_device) 528 or setIfChanged(upnp.UPNP_RENDERING_CONTROL_SERVICE, "CurrentMute", (1-isMuted), PARENT_DEVICE) 529 530 if (changed) then 531 luup.variable_set(HADEVICE_SID, "LastUpdate", os.time(), PARENT_DEVICE) 532 end 230 533 </run> 231 534 </action> … … 237 540 -- Volume up 238 541 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 239 "SetRelativeVolume", upnp.UPNP_RENDERING_CONTROL_SID, 240 {InstanceID="0", Channel="Master", Adjustment=3}) 241 542 "SetRelativeVolume", upnp.UPNP_RENDERING_CONTROL_SERVICE, 543 {InstanceID="0", Channel="Master", Adjustment=3}) 242 544 </run> 243 545 </action> … … 249 551 -- Volume down 250 552 upnp.UPnP_request(luup.devices[lul_device].ip, ipPort, UPNP_RENDERING_CONTROL_URL, 251 "SetRelativeVolume", upnp.UPNP_RENDERING_CONTROL_SID,252 553 "SetRelativeVolume", upnp.UPNP_RENDERING_CONTROL_SERVICE, 554 {InstanceID="0", Channel="Master", Adjustment=-3}) 253 555 </run> 254 556 </action> 255 557 </actionList> 256 558 </implementation> 257
Note: See TracChangeset
for help on using the changeset viewer.