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

Sonos Play Fil VD issues


Question

Posted

Hi all.

 

I have install this Sonos VD to play MP3's at a click of a button.

 

Short files work fine like sound effects but full music tracks only play for about 20 seconds.

 

Can anyone help with this.

 

I have attached the LUA below so you can see what I am using. All you have to do is change the last line to where your MP3 is and the required volume and that's it.

 

Look forward to the reply.

 

Regards,

 

Andy

 

------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- SONOS Play stream...
-- Copyright © 2014 Jean-Christophe Vermandé
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
 
selfId = fibaro:getSelfId();    
ip = fibaro:get(selfId, 'IPAddress');
port = fibaro:get(selfId, 'TCPPort') or 1400;
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)   
      if (duration ~= nil) then
        fibaro:debug("play sent for " .. duration .. " seconds");
        fibaro:sleep(duration);
        stop();
      else
        fibaro:debug("play sent");
        local n = 0;
        currentTransportState = "TRANSITIONING";
        while (currentTransportState == "TRANSITIONING") do
          if (n > 10) then break end;
          getTransportState();
          fibaro:debug(currentTransportState);
          fibaro:sleep(5000);
          n = n + 1;
        end        
        local i = 0;
        currentTransportState = "PLAYING";
        while (currentTransportState == "PLAYING") do
          if (i > 10) then break end;
          getTransportState();
          fibaro:debug(currentTransportState);
          fibaro:sleep(2000);
          i = i + 1;
        end
        fibaro:sleep(1000);
        stop();
      end
      -- update volume with value before tts if different
      if (ttsVolumeIsDifferent == true) then
        setVolume(lastVolume);
        ttsVolumeIsDifferent = false;
      end
    end);    
end
 
setVolume = function(value)
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/RenderingControl/Control",
    -- service type
    "urn:schemas-upnp-org:service:RenderingControl:1",
    -- action
    { name = "SetVolume", service = "urn:schemas-upnp-org:service:RenderingControl:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>" .. tostring(value) .. "</DesiredVolume>",
    -- callback (options)
    function(response)      
      fibaro:debug("Volume set: " .. value);
    end);
end
 
getVolume = function()
  fibaro:log("Get volume, please wait...");
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/RenderingControl/Control",
    -- service type
    "urn:schemas-upnp-org:service:AVTransport:1",
    -- action
    { name = "GetVolume", service = "urn:schemas-upnp-org:service:RenderingControl:1" },
    -- soap body data (options)    
    "<InstanceID>0</InstanceID><Channel>Master</Channel>",
    -- callback (options)
    function(response)
      currentVolume = tonumber(response:match("<CurrentVolume>(.+)</CurrentVolume>") or 0);    
    end);
end
 
getTransportState = function()
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/AVTransport/Control",
    -- service type
    "urn:schemas-upnp-org:service:AVTransport:1",
    -- action
    { name = "GetTransportInfo", service = "urn:schemas-upnp-org:service:AVTransport:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID>",
    -- callback (options)
    function(response)      
      currentTransportState = response:match("<CurrentTransportState>(.+)</CurrentTransportState>") or "";
    end);
end
 
playFile= function(file, 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:" .. file .. "</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

playFile("//192.168.1.247/Music/Incoming.mp3", 70);

Please login or register to see this attachment.

2 answers to this question

Recommended Posts

  • 0
Posted

I'm no programmer but I had the same problem.... I messed with the code and did this.... seems to work...

 

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- SONOS Play stream...
-- Copyright © 2014 Jean-Christophe Vermandé
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------

selfId = fibaro:getSelfId();
ip = fibaro:get(selfId, 'IPAddress');
port = fibaro:get(selfId, 'TCPPort') or 1400;
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

unMute = function()
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/RenderingControl/Control",
    -- service type
    "urn:schemas-upnp-org:service:RenderingControl:1",
    -- action
    { name = "SetMute", service = "urn:schemas-upnp-org:service:RenderingControl:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredMute>0</DesiredMute>",
    -- callback (options)
    function(response)
      fibaro:debug("unMute sent");
    end);
end

play = function(duration)
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/AVTransport/Control",
    -- service type
    "urn:schemas-upnp-org:service:AVTransport:1",
    -- action
    { name = "Play", service = "urn:schemas-upnp-org:service:AVTransport:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID><Speed>1</Speed>",
    -- callback (options)
    function(response)
      if (duration ~= nil) then
        fibaro:debug("play sent for " .. duration .. " seconds");
        fibaro:sleep(duration);
        stop();
        end
        fibaro:sleep(1000);
    end);
end

setVolume = function(value)
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/RenderingControl/Control",
    -- service type
    "urn:schemas-upnp-org:service:RenderingControl:1",
    -- action
    { name = "SetVolume", service = "urn:schemas-upnp-org:service:RenderingControl:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>" .. tostring(value) .. "</DesiredVolume>",
    -- callback (options)
    function(response)
      fibaro:debug("Volume set: " .. value);
    end);
end

getVolume = function()
  fibaro:log("Get volume, please wait...");
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/RenderingControl/Control",
    -- service type
    "urn:schemas-upnp-org:service:AVTransport:1",
    -- action
    { name = "GetVolume", service = "urn:schemas-upnp-org:service:RenderingControl:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID><Channel>Master</Channel>",
    -- callback (options)
    function(response)
      currentVolume = tonumber(response:match("<CurrentVolume>(.+)</CurrentVolume>") or 0);
    end);
end

getTransportState = function()
  return sendSoapMessage(
    -- control url
    "/MediaRenderer/AVTransport/Control",
    -- service type
    "urn:schemas-upnp-org:service:AVTransport:1",
    -- action
    { name = "GetTransportInfo", service = "urn:schemas-upnp-org:service:AVTransport:1" },
    -- soap body data (options)
    "<InstanceID>0</InstanceID>",
    -- callback (options)
    function(response)
      currentTransportState = response:match("<CurrentTransportState>(.+)</CurrentTransportState>") or "";
    end);
end

playFile= function(file, 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:" .. file .. "</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

-- parameters: the file, the volume
playFile("//192.168.1.1/sounds/ti.m4a", 20);

  • 0
Posted

Hi could someone help me please with this VD, I use the above code but I hear no sound.

 

This is the path to my MP3 file:

 

playFile("//192.168.1.251/Users/Thijs/MP3/Burglar-alarm-sound.mp3", 40);

 

DEBUG

 

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...