Sonos plugin

Hi @Lolodomo/@Guessed/@Anker

Now that we have an child board dedicated to the most popular plugins, just like lolodomo has done on the RXTrx433 plugin, can we think about breaking up this plugin board into focussed threads - 40+ pages and growing is becoming overwhelming.

Maybe something like the following, @anker could consider locking his original post as the plugin has evolved beyond almost all recognition now…

Welcome - Please Read First

  • Introduction and set the scene

Plugin Development Discussions

  • just like you are doing with guessed and show what you’ve added
  • Known Issues

Version X.X Released

  • show what you’ve added
  • host any discussions around the new release and new features
  • Known Issues

Text To Speech (TTS. - I can even rename my post to work for all TTS discussions?

  • How the TTS element works,
  • Host any discussions around the limitations/dynamic TTS

New Feature Requests

  • A place where people can submit ideas for your feedback/consideration

Some of these can even be made ‘stickies’ so they always sit at the top.

Such a great job has been done on this plugin and there is a lot to it now, that spacing it out will help people, especially the new ones to Vera.

[quote=“lolodomo, post:620, topic:169644”]Hek, I thing you are on the right direction. Now I see that the plugin uses a UTF-8 encoding for the UPnP request. Maybe Device Spy uses UTF-8 too.
I will try to force a ISO-8859-1 encoding in the plugin to see if it helps.[/quote]

No success whatever the combination of URL and encoding :frowning:
We probably need guessed’s analysis on this point.

Ok.

Where did you find device spy. I can’t seem to find any good download site.

I tries to ISO-8859-1 encode a test lua script (with åäö text) … But the vera would not accept it.

Certainly on Intel web site. Google with “Intel Device Spy”.

I hope guessed still reads the topic…

I summarize the last bugs to be resolved before an official release:

1 - call to MusicServices.ListAvailableServices (function getAvailableServices) does not return while the corresponding UPnP request returns something. Don’t know if it is important but the return value is a big XML string. Maybe a stupid bug relative to the way I call the function ?

2 - TTS is not working well as soon as accents are in the text. Maybe a problem of encoding (URL and/or UPnP stuff) ? Without accents, unfortunately TTS is not usable for certain language.

The calls work, at least in a free-standing test script (attached, with output). There are definitely special characters in the output, so you’d need to look very carefully at any parsing logic to ensure it’s “safe” when processing the responses.

It’s also possible that the call is timing out if it’s got a lot of stuff in it, since I keep the default timeouts fairly short. I ran the test scripts above directly on my Mac, so there’s also a possibility of an issue on the MiOS Lua version (but I doubt it)

2 - TTS is not working well as soon as accents are in the text. Maybe a problem of encoding (URL and/or UPnP stuff) ? Without accents, unfortunately TTS is not usable for certain language.
I've wondered if perhaps another route might work. In an alternate scheme, we "download" the Google TTS output (using [tt]os.execute("wget ...")[/tt]) and put the output [ file ] directly into the MiOS directory (like /www).

Then we tell the Sonos unit to pick it up from there using “another” path (not x-rincon-mp3radio, since it’s causing us grief in other ways…)

Using the command-line of Vera, I can run the following command:

wget --output-document bar.wav --quiet --header="Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3" \ --header="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" \ --user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11" \ "http://translate.google.com/translate_tts?tl=fr&q=test%e9"

and it successfully creates a “bar.wav” file that can be retrieved from Vera using a URL like:
http://veraIP/bar.wav

To avoid concurrency headaches, across Sonos units, we could name the file something like .wav. It’s a bit kludgy, but it does appear to handle the Latin-1 characters correctly, and it’s going to present them to a Sonos unit as ASCII-7 chars (in the filename form) so we’d avoid issues there.

The potential issue is that the Sonos might “start up” prior to the file being fetched using the [backgrounded] WGET call… which would lead to us playing the last file/speech text.

There is a lot of debug code that has crept into the codebase, but this is presumably until the getAvailableServices call can be made to function. If we cannot sort that out, then we should remove it from the code prior to pushing it to apps.mios.com. As there have been drastic changes going in lately, I’ve “reset” the testing clock that I use prior to push, so that people can help stabilize it.

PS: One of the TransportState comparisons appears to be against an inline-constant that has a typo, which will need to be corrected as well. It’s in the restore call.

The following methods have been obsoleted:
[tt]urn:micasaverde-com:serviceId:Sonos1[/tt] “Mute”
[tt]urn:micasaverde-com:serviceId:Sonos1[/tt] “UnMute”
[tt]urn:micasaverde-com:serviceId:Sonos1[/tt] “SetVolume”
[tt]urn:micasaverde-com:serviceId:Sonos1[/tt] “SetFileToPlay”

In favor of their standard counterparts:
[tt]urn:micasaverde-com:serviceId:Volume1[/tt] “Mute”
[tt]urn:upnp-org:serviceId:RenderingControl[/tt] “SetMute”
[tt]urn:upnp-org:serviceId:RenderingControl[/tt] “SetVolume”
[tt]urn:upnp-org:serviceId:RenderingControl[/tt] “SetRelativeVolume”
[tt]urn:upnp-org:serviceId:RenderingControl[/tt] “SetVolumeDB”

[quote=“lolodomo, post:587, topic:169644”][quote=“guessed, post:582, topic:169644”]Lolodomo,
Will look at a few of these over the next few days. Been a little buried @work.

As we look to release this via apps, should we obsolete the old *:device:Sonos actions, for the newer :serviceId: counterparts added a few week back, so as to avoid people getting confused by the duplicate actions (like Mute, etc)?

Might be a good time for me to clean those out since there aren’t many users…[/quote]

  • Mute, UnMute and SetVolume can probably be deleted.

  • SetFileToPlay has not a real interest as covered by SetURIToPlay. I could even add a control in SetURIToPlay to consider that the parameter is a file if it starts with a / ?

  • SetURIToPlay and PlayURI could certainly be merged in one unique callback with a parameter requesting to only load the URI or to load and play it. By the way, I don’t imagine in which cases users want to load something without playing it…[/quote]

@lolodomo,
These errors are coming from this call:

-- Audio inputs status, tmp = ContentDirectory.Browse({ObjectID="AI:", BrowseFlag="BrowseDirectChildren", Filter="", StartingIndex="0", RequestedCount="10", SortCriteria="", Result="", NumberReturned="", TotalMatches="", UpdateID=""}) changed = setIfChanged(SONOS_MR_CONTENT_DIRECTORY.sid, "AudioInputs", extractElement("Result", tmp, ""), PARENT_DEVICE, false)

That are happening as part of the refreshNow call. I see these occurring against my Sonos Connect unit.

What model of Sonos are you running? I’m wondering if this call, or it’s parameters, are somehow model specific. The Sonos Connect units have a LineIn equivalent, but it’s RCA style.

[quote=“lolodomo, post:581, topic:169644”][quote=“jduchon, post:579, topic:169644”]Hello,

I have the plugin working correctly for several weeks and get the same error message Hek has in my log:

luup_log:38: Sonos: error UPnP_request: status=1 statusMsg=500 result=[ Error 500

No Reason
] <0x2c689680>

Thank you all for the great work!

Jerome[/quote]

Bonjour Jérome.

I don’t have this error.
This is something for guessed, the UPnP specialist. ;)[/quote]

@lolodomo,
Do you know where is the Sonos unit getting the URI from?

It seems like a CDN URL, which could change on us without notice. I tried it from home, and can see the Sonos App using the same URI, but couldn’t work out what Metadata they were using, and where they were getting it, to “point” to this to get images (etc).

One way around it would be to create/default a MiOS config parameter like:

RadioURI    http://d1i6vahw24eb07.cloudfront.net/%s

then, if it ever changed, people could tweak a parameter instead of tweaking the code.

[quote=“lolodomo, post:600, topic:169644”]Regarding the tunein radio logo, searching on the tunein web site, I discovered that raidoo logo are here with two different sizes:


In this example, s75560 is the “reference” of the tunein radio.
Amazon CloudFront est donc utilisé.[/quote]

We could. I was being somewhat simplistic by saying that the first call would trap “the bulk” of the problem, and that any continuation into the rest of the code would only give a set of errors if the unit and/or connectivity went down within a short period of time immediately after that call.

The rest, if they error’d out, would be noise, since they wouldn’t then repeat in the logs as badly as was happening without the first check. I put in the original check as I have units that I power down for most of the day, and it was causing large #'s of errors in the log files.

We can always add more, but the likelihood that the connectivity is lost in between, and the resulting “self-correcting” behavior (over the next sample) probably not make it worth the effort.

Either way, I don’t mind.

[quote=“lolodomo, post:607, topic:169644”]I see in an old version that there was no initial test to check if the comm was ok when refreshing data information.

@guessed: in the current version, there is not a check of the status variable after each UPnP call. Would it be more secure to do it ?[/quote]

[quote=“guessed, post:629, topic:169644”]@lolodomo,
Do you know where is the Sonos unit getting the URI from?

It seems like a CDN URL, which could change on us without notice. I tried it from home, and can see the Sonos App using the same URI, but couldn’t work out what Metadata they were using, and where they were getting it, to “point” to this to get images (etc).[/quote]

Unfortunately I did not find where to get this information through UPnP calls.

One way around it would be to create/default a MiOS config parameter like:
RadioURI    http://d1i6vahw24eb07.cloudfront.net/%s

then, if it ever changed, people could tweak a parameter instead of tweaking the code.

Good idea.
TuneInRadioLogoURL would be a better variable name.

[quote=“guessed, post:628, topic:169644”]@lolodomo,
These errors are coming from this call:

-- Audio inputs status, tmp = ContentDirectory.Browse({ObjectID="AI:", BrowseFlag="BrowseDirectChildren", Filter="", StartingIndex="0", RequestedCount="10", SortCriteria="", Result="", NumberReturned="", TotalMatches="", UpdateID=""}) changed = setIfChanged(SONOS_MR_CONTENT_DIRECTORY.sid, "AudioInputs", extractElement("Result", tmp, ""), PARENT_DEVICE, false)

That are happening as part of the refreshNow call. I see these occurring against my Sonos Connect unit.

What model of Sonos are you running? I’m wondering if this call, or it’s parameters, are somehow model specific. The Sonos Connect units have a LineIn equivalent, but it’s RCA style.[/quote]

That’s really weird.
My Sonos is Connect Amp with a RCA line-in too.
Do you think it is the reason of the error 500 mentioned by two other users ?
Do you know what means error 500 ?

To debug that, it would help if you could check the metadata in variableCurrentTrackMetaData.DIDL-Lite. The item in the XML has two attributes named id and parent. Normally, parent should be “AI:” and id should be “AI:0”.

[quote=“guessed, post:626, topic:169644”]The calls work, at least in a free-standing test script (attached, with output). There are definitely special characters in the output, so you’d need to look very carefully at any parsing logic to ensure it’s “safe” when processing the responses.

It’s also possible that the call is timing out if it’s got a lot of stuff in it, since I keep the default timeouts fairly short. I ran the test scripts above directly on my Mac, so there’s also a possibility of an issue on the MiOS Lua version (but I doubt it)[/quote]

That’s really strange. If I put a log just after the call of the function (like you did), the log is never reached !
I don’t think there is a problem of timeout as if I add logs in the UPnP stuff, I can see the HTTP request is run and get a correct result (status = 200). A real mystery.
I will try to force a certain return value in the UPnP stuff to see if the function returns with output parameters correctly set.
Can you tell me where is setup the timeout please ?

I've wondered if perhaps another route might work. In an alternate scheme, we "download" the Google TTS output (using [tt]os.execute("wget ...")[/tt]) and put the output [ file ] directly into the MiOS directory (like /www).

Then we tell the Sonos unit to pick it up from there using “another” path (not x-rincon-mp3radio, since it’s causing us grief in other ways…)

Using the command-line of Vera, I can run the following command:

wget --output-document bar.wav --quiet --header="Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3" \ --header="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" \ --user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11" \ "http://translate.google.com/translate_tts?tl=fr&q=test%e9"

and it successfully creates a “bar.wav” file that can be retrieved from Vera using a URL like:
http://veraIP/bar.wav

To avoid concurrency headaches, across Sonos units, we could name the file something like .wav. It’s a bit kludgy, but it does appear to handle the Latin-1 characters correctly, and it’s going to present them to a Sonos unit as ASCII-7 chars (in the filename form) so we’d avoid issues there.

The potential issue is that the Sonos might “start up” prior to the file being fetched using the [backgrounded] WGET call… which would lead to us playing the last file/speech text.

Interesting alternative.
Note that with this solution we could forget ISO-8859-1 as google URL is working with a URL coded in UTF-8.
What kind of URI will we use ? Could we use “file:” ? If it could solve our problem of ending file, that would be a plus.

PS: One of the TransportState comparisons appears to be against an inline-constant that has a typo, which will need to be corrected as well. It's in the restore call.

Yes, I see it: TRANSIOTIONING

Maybe we can use io.popen instead of os.execute to make sure the google-file ha been fully downloaded before playing it?
Or does os.execute wait aswell if you omit “&”?

I will try some os.execute to generate speech tonight (when the kids are in bed…).

Hello guessed,

My unit is a play:3.

Best,

Jérôme

[quote=“lolodomo, post:632, topic:169644”][quote=“guessed, post:628, topic:169644”]@lolodomo,
These errors are coming from this call:

-- Audio inputs status, tmp = ContentDirectory.Browse({ObjectID="AI:", BrowseFlag="BrowseDirectChildren", Filter="", StartingIndex="0", RequestedCount="10", SortCriteria="", Result="", NumberReturned="", TotalMatches="", UpdateID=""}) changed = setIfChanged(SONOS_MR_CONTENT_DIRECTORY.sid, "AudioInputs", extractElement("Result", tmp, ""), PARENT_DEVICE, false)

That are happening as part of the refreshNow call. I see these occurring against my Sonos Connect unit.

What model of Sonos are you running? I’m wondering if this call, or it’s parameters, are somehow model specific. The Sonos Connect units have a LineIn equivalent, but it’s RCA style.[/quote]

That’s really weird.
My Sonos is Connect Amp with a RCA line-in too.
Do you think it is the reason of the error 500 mentioned by two other users ?
Do you know what means error 500 ?

To debug that, it would help if you could check the metadata in variableCurrentTrackMetaData.DIDL-Lite. The item in the XML has two attributes named id and parent. Normally, parent should be “AI:” and id should be “AI:0”.[/quote]

Sorry, this was in the result of the Browse function that I can find this information.
Could you spy the network to see what call is done when in a Sonos control application you are on your Sonos Connect and click on “Line-In” source to display all the available line-in ? I assume you should see a call to Browse with “AI:” as parameter ?
When it faisl, what message do you get ?

I finally found where was the problem with MusicServices.ListAvailableServices.
In SONOS_MUSICSERVICES, you forgot to define event. And it seems to be important…

Ok, the following code generates an test.wav reachable on
/test.wav

 os.execute("wget --output-document /www/test.wav --quiet "..
				" --header \"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\""..
				" --header \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\""..
				" --user-agent \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11\""..
				" \"http://translate.google.com/translate_tts?tl="..language..
				"&amp;q="..url.escape(defaultValue(lul_settings, "Text", "The quick brown fox jumps over the lazy dog"))..
				"\"")

But how do I make the sonos play it?

Tried modifying say like this(with my vera ip hardcoded). But it didn’t work. Which protocol should I use?

AVTransport.StartAutoplay( {InstanceID=instanceId, ProgramURI="http://192.168.178.100/test.wav", ProgramMetaData="", Volume=volume, IncludeLinkedZones=1, ResetVolumeAfter=1})

New changes in the trunk:
Bug relative to MusicServices fixed
Typo error fixed in restorePlaybackContext