This isn’t so much a question about how to fix an issue, as a matter of fact, I know how. I’m curious why I have to fix this issue in my configuration. From my perspective it looks like the default behavior is wrong.
So here’s the setup. I’m running NGINX plus DuckDNS/Let’s Encrypt. I have my external URL configured to the DuckDNS hostname and internal URL is set to http://homeassistant.local:8123. NGINX handles this excellently. Maybe I should pause and say I’m not entirely confident in my understanding of what Home Assistant does with the internal URL. My intent is to use it for local access. It doesn’t make sense to me to use the external URL when I’m home and on the same network.
Google TTS, according to all the documentation, only works with an externally accessible URL, but it uses the “Internal URL” field in the Home Assistant configuration by default. I know I can fix this by setting base_url in the TTS configuration but why should I have to do this? The correct value exists in the external URL field and unless the internal URL is externally accessible, that field wont work. So why does it default to this value?
I couldn’t find that anywhere in the documentation. However, I found this:
When do you need to set base_url here?
The general answer is “whenever the global internal URL set in the configuration of Home Assistant is not adequate to allow the say service to run”. The say service operates by generating a media file that contains the speech corresponding to the text passed to the service. Then the say service sends a message to the media device with a URL pointing to the file. The device fetches the media file at the URL and plays the media. Some combinations of a media device, network configuration and Home Assistant configuration can make it so that the device cannot fetch the media file. Text-to-speech (TTS) - Home Assistant
So, in my understanding, you only need to change base_url if the media player that you are trying to play the TTS message on cannot access your internal_url. However, the TTS engine itself should work just fine without base_url.
There should be a directory called tts in your configuration directory. When you try to use a TTS message that hasn’t been used used before, a new mp3 file should be created in <configuration directory>/tts/. This way, you can verify if the TTS engine works even if your media player is unable to actually play the message.
Perhaps I misspoke, not so much documentation but forum posts with the same issue. I was digging for a reference and rereading some of the posts I think I may have a better understanding of the problem. The Google assistant speakers use hardcoded DNS servers and are therefore unable to resolve .local domains. So, the fixes appear to be, if I understand correctly:
Use an external URL that they can resolve as the internal URL
Use an IP address for your internal URL so no resolution is necessary
Block the Google homes from using their DNS server, they will fall back to the one assigned by DHCP and gain the ability to resolve .local domains
But I’m honestly not satisfied with this as the answer. Still seems there’s a known limitation with the Google platform, and having the default behavior avoid this limitation seems wise.
Cant really add anything helpful other than my own experience of doing or trying no.3.
Although they continued to work, I experienced intermittent delays in both Google’s own functionality and between HA & google. So much so that I could not live with it so reverted back.
Interesting. Definitely starting to look like a Google bug. I just tried with the hard coded IP as my internal URL, it seems to work though I dislike having static IP addresses on my network. Not for any good reason other than it’s more configuration that needs to be noted or backed up and I’m inherently lazy. I guess the longer I meditate on this the less I think TTS should change its behavior. We should be using internal URLs when talking to internal devices.
When I originally asked the question I was under the mistaken impression Google required the mp3 be passed through an external server on the way to the speaker, but since using the IP works, that’s clearly not the issue…