Vielen Dank.
In der Tat hat der Sonos Commander so dermaßen viel Coe, dass ich etwas lost bin.
Button1:
selfId = fibaro:getSelfId();
ip = fibaro:get(selfId, 'IPAddress');
port = fibaro:get(selfId, 'TCPPort');
currentTransportState = "";
lastTransportState = "";
currentVolume = 0;
lastVolume = 0;
ttsVolumeIsDifferent = false;
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 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" .. 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)
fibaro:debug("Play");
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
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- SONOS Radio
-- Version 0.0.1 pre-release
-- Copyright (C) 2015 Nicolas Dörig
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
playMusic= function(music, volume)
return sendSoapMessage(
-- control url
"/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-file-cifs://" .. music .. "</CurrentURI>,<CurrentURIMetaData></CurrentURIMetaData>",
-- 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
play();
end);
end
-- Globale Variabel abfragen & verwenden
if fibaro:getGlobalValue("Wochentag") == "" then
playMusic("Wochentag", nil);
else
playMusic(fibaro:getGlobalValue("Wochentag"), nil);
end
fibaro:call(selfId, "setProperty", "ui.Label1.value", "Musik läuft..."); --Status Anzeige im VD Interface
Button 2:
selfId = fibaro:getSelfId();
ip = fibaro:get(selfId, 'IPAddress');
port = fibaro:get(selfId, 'TCPPort');
currentTransportState = "";
lastTransportState = "";
currentVolume = 0;
lastVolume = 0;
ttsVolumeIsDifferent = false;
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 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" .. 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)
fibaro:debug("Play");
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
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- SONOS Radio
-- Version 0.0.1 pre-release
-- Copyright (C) 2015 Nicolas Dörig
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
playMusic= function(music, volume)
return sendSoapMessage(
-- control url
"/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-file-cifs://" .. music .. "</CurrentURI>,<CurrentURIMetaData></CurrentURIMetaData>",
-- 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
play();
end);
end
-- Globale Variabel abfragen & verwenden
if fibaro:getGlobalValue("Test") == "" then
playMusic("Test", nil);
else
playMusic(fibaro:getGlobalValue("Test"), nil);
end
fibaro:call(selfId, "setProperty", "ui.Label1.value", "Musik läuft..."); --Status Anzeige im VD Interface
Von mir kommen nur die beiden Variablen “Wochentag” und “Test” am Ende der beiden Button.
Vielen Dank.