Aller au contenu
Rem's

Sonos Play Stream (Musiques, Etc...)

Recommended Posts

Cher Krikoff,

 

J'ai lu dans un de tes posts que l'on pouvait déclencher le titre en cours ou peut être faire appel à  d'autres .... Déclencher un sons, une sonnerie.

 

Tu parles d'utiliser la fonction "setAVtransportURI"

 

Pourrais tu m'en dire plus, voir me filer le code en question.

D'avance merci pour ton aide, je suis sur que d'autres "fibariste" seront également intéressés.

 

 

Modifié par Krikroff
Modification du titre
  • Upvote 1

Partager ce message


Lien à poster
Partager sur d’autres sites

Sur la base de mon code pour le TTS, une nouvelle fonction "playFile"

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- SONOS Play stream...
-- Copyright (C) 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

-- en paramètres: le fichier, puis le volume...
playFile("//HOME-SERVER/Musique/CD/Dream Theater/A Change of Seasons/01-A Change of Seasons [Medley].flac", 20); 

Voilou ;)

Partager ce message


Lien à poster
Partager sur d’autres sites

J'ai mis ce code dans un module virtuel, j'ai renseigné l'adresse IP et le Port

J'ai renseigné l'IP de l'iPad mais cela me retourne un message d'erreur.

 

Une idée

 

 

post-114-0-07499200-1397315080_thumb.png

post-114-0-39901800-1397315398_thumb.png

Partager ce message


Lien à poster
Partager sur d’autres sites

Salut Krikoff,

 

J'utilise ta fonction PlayFile pour lire des annonces vocales synthétisées qui sont enregistrées sur mon nas (alarme activée, arrosage en cours, sortir les poubelles, etc.). C'est vraiment très pratique :D

Je préfère cette fonction au TTS qui est finalement pas très agréable au quotidien (temps de latence, la voix pas terrible, problème des accents, fin de phrase tronquée)

Par contre, penses-tu qu'il est possible d'adapter le code pour reprendre la lecture en cours (radio, playlist...) ?

 

Merci ! @+

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour

J'ai le même problème qu Rem'S ci-dessus avec le message d'erreur mais en mettant l'adresse IP du SONOS et 1400 ou IP du PC ou se trouve la chanson ?

Une idée

Merci

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour Krilkroff,

 

Merci encore pour ton plugin SONOS, ça marche nickel. Je me régale avec ton TTS. Grâce à  toi je revis l'ambiance quai de gare et ses annonces si ....... belles ! (lol)

Dans un autre module, j'ai mis le script du dessus, mon soucis est ce message qui apparait dans Sonos : "Impossible de lire ... mon fichier... car serveur introuvable.

 

//Home_synology/volume1/music/03_LAST_NIGHT_(DIDDY_feat_KEYSHIA_COLE).mp3 (avec un autre fichier en ".flac" c'est pareil)

 

Aurais tu une idée, d'avance merci

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour a tous,

 

tout d'abord je voudrai te remerrci Krilkroff (ou JC, je ne sais pas trop bien encore) pour tout ce que tu m'as apporté afin de pouvoir commencer à  installer mon nouveau matos.

 

j'ai un Fibaro HC2 et une bar sons SONOS. j'ai reussis sans soucis à  utiliser ta solution de TTS mais je n'arrive pas à  utiliser ta fonction pour lire des PM3...

 

est ce que je dois ajouter cette fonction dans un device virtuel existant (le SONOS player)? ou dans un nouveau device virtuel? ou dans une scene? ou quelque part d'autre???

 

merci beaucoup pour ton aide et l'aide de toute la communauté.

 

Steven

Partager ce message


Lien à poster
Partager sur d’autres sites

Il faut utiliser le code dans le bouton d'un module virtuel par exemple, avec des modifications du code dans une scène en V4 mais attendons une V4 stable ;)

Partager ce message


Lien à poster
Partager sur d’autres sites

Merci beaucoup pour ta réponse.

 

je vais essayer avec un bouton mais je ne pense pas que je puisse simuler le click d'un bouton avec une scene... sinon je vais essayser de modifier le code pour le mettre dans une scene (j'ai la version 4.030 qui est stable de ce que j'ai compris :2: ...)

Partager ce message


Lien à poster
Partager sur d’autres sites

Depuis une scène tu peux faire un call sur un bouton d'un vd 

fibaro:call(VD_ID, "pressButton", BT_NUMBER);

;)

Partager ce message


Lien à poster
Partager sur d’autres sites

tout d'abord je voudrai te remerrci Krilkroff (ou JC, je ne sais pas trop bien encore)

tu as plusieurs choix dispo:

- Krikroff

- JC

- Dieu

- Tu peux essayer trou du cul mais je suis pas sur qu'il te réponde :D

Partager ce message


Lien à poster
Partager sur d’autres sites

Ben si tu vois

En revanche Dieu non ce n'est pas mon truc. Par contre toi tu peux m'appeler chaton des bois si tu veux mon biquet

Évidemment je plaisante, même pas en rêve pour chaton des bois

Envoyé de mon smartphone

  • Upvote 2

Partager ce message


Lien à poster
Partager sur d’autres sites

Ho mon chaton des bois, c est ti pas mignon sa xd.

Partager ce message


Lien à poster
Partager sur d’autres sites

Cher Krikroff CdB (Chaton des Bois),

 

tout fonctionne ou presque... le bouton fonctionne et je peux jouer des sons de mon NAS (conseil pour ceux qui veulent faire la même chose, le MP3 dans le NAS doit faire partie de la librairie du SONOS pour que ca fonctionne...).

 

j'ai ensuite créé une nouvelle scene et mis ce code:

fibaro:call(VD_ID, "pressButton", Button481);

ca me fait cette erreur:

 Runtime error: /opt/fibaro/FibaroSceneAPI.lua:252: attempt to concatenate local 'deviceID' (a nil value)

 

je suis malin et j'ai donc changé et testé avec ce code:

fibaro:call(VD_ID, "pressButton", "Button481");

mais ca me refait de nouveau cette erreur..

 Runtime error: /opt/fibaro/FibaroSceneAPI.lua:252: attempt to concatenate local 'deviceID' (a nil value)

 

maintenant je ne suis plus malin du tout et je viens pleurer vers toi....

qu'ai je fait faut encore...

 

aussi il y a t il quelque part une doc sur LUA et le fonction methode ect qui existe?

 

merci encore 1000 fois pour ton aide.

 

Steven

  • Upvote 1

Partager ce message


Lien à poster
Partager sur d’autres sites

Le problème ne vient pas du Button481 mais d'une variable. D'où sort tu ton VD_ID.

Partager ce message


Lien à poster
Partager sur d’autres sites

salut Shad....

 

Heuuuu... je ne sais pas trop... j'ai assez bêtement copié le code de Krikroff...

 

je ne trouve pas beaucoup de doc sur LUA donc j'avance assez aveuglément...

je devrai mettre qqch dans VD_ID?

 

merci

Partager ce message


Lien à poster
Partager sur d’autres sites

VD_ID c'est l'ID de ton vd module virtuel et pour le bouton il faut passer le numéro de l'élément correspondant... En fait tu comptes juste les éléments jusqu'au bouton.

Envoyé de mon smartphone

Partager ce message


Lien à poster
Partager sur d’autres sites

merci pour cet info en effet ca fait du sens!

 

je continue avec mes questions (betes).... au moins ca fera de la documentation pour les autres....

mais je trouve le device ID de mes senseurs Fibaro mais pas le device ID des device virtuel... comment faire????

 

merci merci merci

Partager ce message


Lien à poster
Partager sur d’autres sites

 Quand tu cliques sur la clé (en haut à  droite de ton module virtuel) pour en modifier le contenu, tu le retrouves dans l'adresse du navigateur (à  la fin).

Partager ce message


Lien à poster
Partager sur d’autres sites

 Le forum est là  pour cela. ;)

Partager ce message


Lien à poster
Partager sur d’autres sites

en fait... je suis assez nul et ca ne marche toujours pas...

2gx0akk.png

 

et j'ai mis comme code dans la scene:

--[[
%% properties

%% globals
--]]

fibaro:call(16, "pressButton", 16);

ca devrait donc jouer... mais evidemment ca ne joue pas...

 

merci au Ninja et au super héro pour votre aide....

 

Steven

Partager ce message


Lien à poster
Partager sur d’autres sites

ouais mais avant de faire une scène, vérifie que ton virtual device fonctionne.

Regarde les debug.

Partager ce message


Lien à poster
Partager sur d’autres sites

@stevengva, il faut vraiment compter les éléments et ne pas faire attention au numéro qui correspond au groupe d’éléments et pas à  l’élément ;)  

Partager ce message


Lien à poster
Partager sur d’autres sites

×