Sonos - Control the device and get status
Posted: Monday 24 July 2017 16:38
Since I'm experiencing problems with the new python plugin system, I decided to recreate my used plugins to LUA code.
For Sonos this is almost done. I created two functions (for now) to control the player and volume of the device.
I created some functions to get to status of the device too, but this is not completely finished at the moment.
The status of the device and volume levels can be fetched without a problem, but I'm not happy yet of the output of what is playing.
This does work, but the way it is shown on the virtual device is not yet perfect. I will share this part when it is finished.
The function to control the player:
How to use it:
The function to control volume and mute:
How to use it:
Function to get status:
How to use it:
Function to get volume/mute status:
How to use it:
I'm using this at the moment attached to virtual devices to control the player, it's volume and to see what is playing.
The function to get information are stored in a timed LUA script, which works fine.
Updates are done every minute and for me that is fast enough.
Update with title information:
For Sonos this is almost done. I created two functions (for now) to control the player and volume of the device.
I created some functions to get to status of the device too, but this is not completely finished at the moment.
The status of the device and volume levels can be fetched without a problem, but I'm not happy yet of the output of what is playing.
This does work, but the way it is shown on the virtual device is not yet perfect. I will share this part when it is finished.
The function to control the player:
Code: Select all
function SonosControl(Device_Sonos_IP,command) -- Play, Stop, Pause, Next, Previous
if (command == "Play") or (command == "Stop") or (command == "Pause") or (command == "Next") or (command == "Previous")
then
Device_Sonos_Port = "1400"
Device_Sonos_url = "/MediaRenderer/AVTransport/Control"
Device_Sonos_Method = "urn:schemas-upnp-org:service:AVTransport:1#" .. command
url = ('curl --header \'SOAPACTION: ' .. Device_Sonos_Method .. '\' --data \'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:' .. command .. ' xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Speed>1</Speed></u:' .. command .. '></s:Body></s:Envelope>\' http://' .. Device_Sonos_IP .. ':' .. Device_Sonos_Port .. '' .. Device_Sonos_url .. '')
io.popen(url .. ' &')
end
end
Code: Select all
SonosControl("192.168.0.2","Play") -- Starts playing on Sonos device with IP address 192.168.0.2
SonosControl("192.168.0.2","Pause") -- Pauses on Sonos device with IP address 192.168.0.2
SonosControl("192.168.0.2","Stop") -- Sops playing on Sonos device with IP address 192.168.0.2
SonosControl("192.168.0.2","Next") -- Next song on Sonos device with IP address 192.168.0.2
SonosControl("192.168.0.2","Previous") -- Previous on Sonos device with IP address 192.168.0.2
Code: Select all
function SonosVolume(Device_Sonos_IP,command,value) -- Volume -> 0-100, Mute -> On/Off
if ((command == "Volume") or (command == "Mute")) and
((value == "Off") or (value == "On") or ((tonumber(value) >= 0) and (tonumber(value) <= 100)))
then
if (value == "Off") then value = 0
elseif (value == "On") then value = 1
end
Device_Sonos_Port = "1400"
Device_Sonos_url = "/MediaRenderer/RenderingControl/Control"
Device_Sonos_Method = "urn:schemas-upnp-org:service:RenderingControl:1#Set".. command
url = ('curl --header \'SOAPACTION: ' .. Device_Sonos_Method .. '\' --data \'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Set' .. command ..' xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel><Desired' .. command ..'>' .. value .. '</Desired' .. command ..'></u:Set' .. command ..'></s:Body></s:Envelope>\' http://' .. Device_Sonos_IP .. ':' .. Device_Sonos_Port .. '' .. Device_Sonos_url .. '')
io.popen(url .. ' &')
end
end
Code: Select all
SonosVolume("192.168.0.2","Volume", 15) -- Sets volume to 15% for Sonos device with IP address 192.168.0.2
SonosVolume("192.168.0.2","Mute", "On") -- Mutes Sonos device with IP address 192.168.0.2
SonosVolume("192.168.0.2","Mute", "Off") -- Unmutes Sonos device with IP address 192.168.0.2
Code: Select all
function SonosGetStatus(Device_Sonos_IP)
Device_Sonos_Port = "1400"
Device_Sonos_url = "/MediaRenderer/AVTransport/Control"
Device_Sonos_Method = "urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo"
-- config ---------------------------------------------------------
url = ('curl --header \'SOAPACTION: ' .. Device_Sonos_Method .. '\' --data \'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetTransportInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetTransportInfo></s:Body></s:Envelope>\' http://' .. Device_Sonos_IP .. ':' .. Device_Sonos_Port .. '' .. Device_Sonos_url .. '')
local f = io.popen(url)
line = f:read()
i, j = string.find(line, '<CurrentTransportState>')
ValueStart = j+1
i, j = string.find(line, '</CurrentTransportState>')
ValueStop = i-1
SonosResult = string.sub(line, ValueStart, ValueStop)
return SonosResult
end
Code: Select all
print(SonosGetStatus("192.168.0.2") -- Gets player status from Sonos device with IP address 192.168.0.2
Code: Select all
function SonosGetVolume(Device_Sonos_IP,command) -- Volume, Mute
Device_Sonos_Port = "1400"
Device_Sonos_url = "/MediaRenderer/RenderingControl/Control"
Device_Sonos_Method = "urn:schemas-upnp-org:service:RenderingControl:1#Get" .. command
-- config ---------------------------------------------------------
url = ('curl --header \'SOAPACTION: ' .. Device_Sonos_Method .. '\' --data \'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Get'.. command .. ' xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel></u:Get'.. command .. '></s:Body></s:Envelope>\' http://' .. Device_Sonos_IP .. ':' .. Device_Sonos_Port .. '' .. Device_Sonos_url .. '')
local f = io.popen(url)
line = f:read()
i, j = string.find(line, '<Current' .. command .. '>')
ValueStart = j+1
i, j = string.find(line, '</Current' .. command .. '>')
ValueStop = i-1
SonosResult = string.sub(line, ValueStart, ValueStop)
if (command == "Mute") and (SonosResult == "0") then SonosResult = "Off"
elseif (command == "Mute") and (SonosResult == "1") then SonosResult = "On"
end
return SonosResult
end
Code: Select all
print(SonosGetVolume("192.168.0.2","Volume") -- Gets volume status from Sonos device with IP address 192.168.0.2
print(SonosGetVolume("192.168.0.2","Mute") -- Gets mutestatus from Sonos device with IP address 192.168.0.2
The function to get information are stored in a timed LUA script, which works fine.
Updates are done every minute and for me that is fast enough.
Update with title information:
Code: Select all
function SonosGetTitle(Device_Sonos_IP)
Device_Sonos_Port = "1400"
Device_Sonos_url = "/MediaRenderer/AVTransport/Control"
Device_Sonos_Method = "uurn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo"
-- config ---------------------------------------------------------
url = ('curl --header \'SOAPACTION: ' .. Device_Sonos_Method .. '\' --data \'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetPositionInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Channel>Master</Channel></u:GetPositionInfo></s:Body></s:Envelope>\' http://' .. Device_Sonos_IP .. ':' .. Device_Sonos_Port .. '' .. Device_Sonos_url .. '')
local f = io.popen(url)
line = f:read()
if string.find(line, "spdif") and not string.find(line, "streamContent")
then
-- Result
SonosResult = "Playing from external source"
elseif string.find(line, "dc:creator")
then
-- Title
i, j = string.find(line, 'dc:title>')
ValueStart = j+1
i, j = string.find(line, '</dc:title')
ValueStop = i-1
SonosTitle = string.sub(line, ValueStart, ValueStop)
-- Artist
i, j = string.find(line, 'dc:creator>')
ValueStart = j+1
i, j = string.find(line, '</dc:creator')
ValueStop = i-1
SonosArtist = string.sub(line, ValueStart, ValueStop)
-- Result
SonosResult = SonosTitle .. ' - ' .. SonosArtist
else
--Radio/streaming title
i, j = string.find(line, 'streamContent>')
ValueStart = j+1
i, j = string.find(line, '</r:streamContent')
ValueStop = i-1
SonosTitle = string.sub(line, ValueStart, ValueStop)
-- Radio Station
i, j = string.find(line, 'dc:title>')
ValueStart = j+1
i, j = string.find(line, '</dc:title')
ValueStop = i-1
SonosRadio = string.sub(line, ValueStart, ValueStop)
SonosRadioFirst, SonosRadioLast = SonosRadio:match("([^.]+).([^.]+)")
SonosResult = SonosTitle .. ' @ ' .. SonosRadioFirst
end
--Adding music source
if string.find(line, "mp3radio")
then
SonosResult = SonosResult .. " (Radio)"
elseif string.find(line, "spotify")
then
SonosResult = SonosResult .. " (Spotify)"
end
--Formating string
SonosResult = string.lower(SonosResult)
SonosResult = string.gsub(" "..SonosResult, "%W%l", string.upper):sub(2)
SonosResult = string.gsub(SonosResult, "&Amp;Amp;", "&")
SonosResult = string.gsub(SonosResult, "&Amp;", "&")
SonosResult = string.gsub(SonosResult, "≪", "<")
SonosResult = string.gsub(SonosResult, "≫", ">")
return SonosResult
end