hklages / node-red-contrib-sonos-plus

A set of Node-RED nodes to control SONOS player in your local network.
MIT License
75 stars 14 forks source link

group.play.streamhttp command won't accept an IP address or local name in URL referencing local device #275

Closed gourdo1 closed 6 months ago

gourdo1 commented 6 months ago

Description

Basically as in title. I setup my Sonos to play an .mp3 file on the local HomeAssistant device that's also running NodeRED. However, any URL pointing to the .mp3 file only works as long as the URL contains a DNS name (in my case xxxxxx.duckdns.org:9123). Local IP addresses, (192.168.1.x, 127.0.0.1) and local hostnames like localhost and homeassistant.local do not work. This is despite all of the above working from a browser on a device in the same LAN.

When Sonos doesn't play, there is no specific debug message in NodeRED either, just a msg.payload showing the chosen URL, which is the same message received when it does play properly.

What node/command (topic)/state (payload)

node: <--- Universal --> command: <--- group.play.streamhttp --> state: <--- ? -->

In case of a bug: Are you able to reproduce the error

<--- yes -->

Versions and Infrastructure

what system: Raspberry Pi 4 8GB, running HAOS:

hklages commented 6 months ago

Hi.

group.play.streamhttp is for a radio stream from the internet - usually a radio station like BBC, ...

Please try group.queue.uri

Does it work (at least with the ip address such as 192.168.x.y)?

best regards Henning

On Fri, Dec 15, 2023 at 11:31 AM gourdo1 @.***> wrote:

Description

Basically as in title. I setup my Sonos to play an .mp3 file on the local HomeAssistant device that's also running NodeRED. However, any URL pointing to the .mp3 file only works as long as the URL contains a DNS name. Local IP addresses, (192.168.1.x, 127.0.0.1) and local hostnames like localhost and homeassistant.local do not work. This is despite all of the above working from a browser on a device in the same LAN.

When Sonos doesn't play, there is no debug message in NodeRED either, just a msg.payload showing the chosen URL, which is the same message received when it does play properly. What node/command (topic)/state (payload)

node: command: state: In case of a bug: Are you able to reproduce the error Versions and Infrastructure

what system: node-red-contrib-sonos-plus version: Node-RED version: NodeJS version:

— Reply to this email directly, view it on GitHub https://github.com/hklages/node-red-contrib-sonos-plus/issues/275, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEDZCHYBVG77VRQNU4FCYZ3YJQRGFAVCNFSM6AAAAABAWHPSWKVHI2DSMVQWIX3LMV43ASLTON2WKOZSGA2DGNBSHAYTSNQ . You are receiving this because you were assigned.Message ID: @.***>

gourdo1 commented 6 months ago

Hmmm, so group.queue.uri doesn't seem to work. Is it supposed to queue a url that's then played with group.play.queue next?

I tried group queue.uri on its own, then group queue.uri followed by group.play.queue as well as group queue.uri followed by group.play, then the above with a 5 second delay in between nodes. In each case, it ignored the provided URL (DNS name or IP address) and played what was previously in the queue (a Spotify track).

group.play.streamhttp continues to work on its own, but only with a DNS name.

hklages commented 6 months ago

Ok.

In general it is recommended to use the SONOS-Queue to play songs because most songs are in the form of a file. But in some cases there are no files but instead there is a stream - for instance a radio station. I created the streamhttp exactly for the second case and I am bit surprised, that it works with your "xxxxxx.duckdns.org:9123". My command adds a prefix "x-rincon-mp3radio" to your name to identify a stream.

Lets go a step back. I have a few questions.

best regards, Henning

On Fri, Dec 15, 2023 at 11:21 PM gourdo1 @.***> wrote:

Hmmm, so group.queue.uri doesn't seem to work. Is it supposed to queue a url that's then played with group.play.queue next?

I tried group queue.uri on its own, then group queue.uri followed by group.play.queue as well as group queue.uri followed by group.play, then the above with a 5 second delay in between nodes. In each case, it ignored the provided URL (DNS name or IP address) and played what was previously in the queue (a Spotify track).

group.play.streamhttp continues to work on its own, but only with a DNS name.

— Reply to this email directly, view it on GitHub https://github.com/hklages/node-red-contrib-sonos-plus/issues/275#issuecomment-1858560718, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEDZCH5IOYYMLIB4HKBOYNLYJTEN7AVCNFSM6AAAAABAWHPSWKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNJYGU3DANZRHA . You are receiving this because you were assigned.Message ID: @.***>

gourdo1 commented 6 months ago

Sorry for delay as I was out of town...

Lets go a step back. I have a few questions.

  • Why do you want to play a single mp3 file? (In case you want to play just a "notification" you can you group.play.notification)

So it's for an alarm system in which I want to use Sonos speakers which are placed throughout my home for a short recorded preamble message followed by a 5 minute alarm sound, all contained in that single mp3 file. I tried group.play.notification and it gives me this error on the Sonos app: Unable to play 'alarm_final.mp3' - the connection to 192.168.2.4:9123 was lost.

  • Where is the file stored? Home Assistant recommendation is to store served files in the "www" folder. (Example to call that file in the browser: http://192.168.178.21:8123/local/doorbell.mp3 where 192.168.178.21 is the ip address of HA)

Yes. The file is placed in /config/www and is accessed via https://192.168.2.4:9123/local/alarm_final.mp3 (in fact when I click this link in github in my browser, it starts playing the file). My HA runs on a non-default port, but I'm pretty sure port isn't the issue as I can access the mp3 file multiple ways, including through group.play.streamhttp as long as I use the external DNS name of the server.

  • When using the group.queue.uri: Can you have a look at the queue (for instance group.get.queue). Is your file added to the queue? If yes you can send a group.clear.queue before. Then the file should be played.

Yup, I get a 51 object array, with the last object being my file...

So... I re-built the flow. It now clears the queue first, then I call my mp3 file with group.queue.uri, then I get the queue which now returns a single object array that looks like this in the debug node:

{"id":"Q:0/1","title":"alarm_final.mp3","artist":"","album":"","description":"","uri":"https://192.168.2.4:9123/local/alarm_final.mp3","artUri":"http://192.168.2.225:1400/getaa?u=https%3a%2f%2f192.168.2.4%3a9123%2flocal%2falarm_final.mp3&amp;v=5","metadata":"","sid":"","serviceName":"","upnpClass":"object.item","processingType":"queue"}

Then I play the queue with group.play.queue. The file doesn't play and the Sonos app still returns:

Unable to play 'alarm_final.mp3' - the connection to 192.168.2.4:9123 was lost

By the way, the reference to 192.168.2.225 seems to be the IP of my Sonos Arc... So I guess it's looking there for album art(?)

In any case, using the exact same methodology as above with all the queue commands, but changing the .mp3 URL to [my_ha_server_address].duckdns.org:9123 instead of an IP address works fine(!)

So I would guess that streamhttp isn't the underlying issue after all... I then re-tried group.play.notification with these substitutions in the URL:

Interestingly, all fail except for the last one.

hklages commented 6 months ago

Thanks for testing that.

  1. Lets verify the mp3 file. Please unzip and copy the doorbell.mp3 to the www directory and check that. This file works on many installation and should also work on yours (play notification, in queue). doorbell.zip

I assume that file also results in a "connection .... was lost" error.

  1. Do you have installed duckdns as Home Assistant Add On? Can you stop that add von 5 minutes and try the group.play.notification?
gourdo1 commented 6 months ago

Thanks for testing that.

1. Lets verify the mp3 file. Please unzip and copy the doorbell.mp3 to the www directory and check that. This file works on many installation and should also work on yours (play notification, in queue).
   [doorbell.zip](https://github.com/hklages/node-red-contrib-sonos-plus/files/13700574/doorbell.zip)

I assume that file also results in a "connection .... was lost" error.

Yes. 'Unable to play 'doorbell.mp3' - the connection to 192.168.2.4:9123 was lost'

I hear a doorbell sound when I use the duckdns URL and no error message in the Sonos app.

2. Do you have installed duckdns as Home Assistant Add On? Can you stop that add von 5 minutes and try the group.play.notification?

Yes duckdns is installed as an add-on in HA. I stopped the add-on and there's no difference even after 10 minutes -- the doorbell sound still plays when using duckdns.org URL. However, when I ping my duckdns dnsname, it still properly resolves to my external WAN IP, so not sure how long it would have to be disabled for the hostname association to time out, if that's what you're trying to get at...

gourdo1 commented 6 months ago

So I just installed the Sonos integration in Home Assistant. Not sure why I didn't try before, but it exposes a media player entity that I can use to theoretically play audio files in NodeRED similar to your integration.

... and it faces the same issue of only playing against my duckdns hostname, and not an internal IP.

At this point, I'm guessing the issue has more to do with Sonos itself not accepting a local file to play. Maybe they just don't like the idea of someone playing their own local files as opposed to paid or at least integrated services so they block IP addresses? Dunno, but I guess it's not a limitation of your implementation after all.

hklages commented 6 months ago

Agree - it is not a limitation of my implementation.

I am able to play local files on Home Assistant, from Synology NAS, from other file server. So in general SONOS accepts these local files (even only http instead of https)

Something in the DuckDNS / Home Assistant combination is not supported from SONOS but I have no idea how to overcome that.

If you have another server you could put your files on that server. Maybe that works.

Another idea is to use the SONOS app and add the www directory as "library" and then select it as an library item. There are several commands to do ti.

gourdo1 commented 6 months ago

I even went a step further and went to the builtin web UI for my Sonos Arc... which has a ping utility as well as tracert. (http://192.168.2.225:1400/tools.htm) and not only can it ping the HA server's IP, but it can tracert and determine the local hostname for the server from its perspective:

running /usr/bin/traceroute 192.168.2.4
traceroute to 192.168.2.4 (192.168.2.4), 30 hops max, 46 byte packets
 1  homeassistant.localdomain (192.168.2.4)  0.941 ms  0.821 ms  0.380 ms

Yet again, using that as the hostname utterly fails. Sonos doesn't like using IPs/names it thinks are local.

The reaosn i want to use the HA server to host the file is that everything is self-contained. I don't have to worry about yet another device being available as long as HA is up. I didn't want to rely on the duckdns because that's another potential point of failure when my HA server's static IP would be more reliable long-term. In any case, for now, I'll stick to the duckdns name and see if I can find out more about the Sonos limitations.

gourdo1 commented 6 months ago

Ok, so I think I know what's going on. I tried a different dynamic DNS service for my HA server and oddly, it failed to work...

Then I found a thread here, which hints at the issue: https://github.com/home-assistant/core/issues/55223

Basically a couple years ago, it seems Sonos added more stringent TLS certificate checking to the system, I assume for security purposes. Since I'm using https for my HA server and the certificate is literally for the duckdns name, it plays just fine for that DNS name, but any other IP address or hostname I try that references the same server results in a mismatched SSL certificate hostname(!) and SOnos refuses to play... albeit with a cryptic error message that doesn't tell you what the actual problem is.

So I think I could either turn off SSL (not the best idea) or create a new certificate to include the internal IP or alternate internal hostname, etc.

I think the mystery is finally solved!

hklages commented 6 months ago

Thanks for solving the "mystery".