As many, I’m using Nabu Casa to connect Home Assistant to Google Home. And as many, it has become close to unusable over the last few months. However, @balloob mentioned a fix that sounds great in the Github issue that revolves around the recent Nabu Casa Problems:
My setup is quite straight forward:
Google Home devices are in my Internet of Shit VLAN
Home Assistant is in my server VLAN
Traffic between these VLANs is firewalled, but Google Home Devices can talk to the Home Assistant server on TCP 8123 (this has been verified) and Home Assistant server can talk to Internet of Shit VLAN (traffic is not filtered in this direction)
An mDNS reflector is running between these VLANs
However the OnOff command apparently is sent via Nabu Casa and not locally, as the log says
Google Assistant sent command OnOff by Home Assistant Cloud
not
Google Assistant sent command OnOff (via local) by Home Assistant Cloud
What am I missing? If I missed nothing, any other idea where to look at?
Coming from the same Github issue, so I’m subscribing to this thread. Wonder if it is possible to use the Local Fulfillment feature as described.
I have the Google Assistant manual integration instead of Nabu Casa, my HA instance is in the same VLAN as the rest of IoT devices (including Google Home Minis and Nest Minis), and mDNS is allowed and working (as far as I can test).
My HA uses HTTPS and it’s served on port 443. Could it be the Google devices are trying to reach it by its local IP or .local domain instead of the external URL, and are stopping at that point due to an invalid certificate?
Following the documentation in the PR to set up Actions on Google (only for the manual integration, I assume this is unnecessary if you use Nabu Casa).
Ensuring Home Assistant can respond to HTTP requests from the Google devices.
The Local Fulfillment API currently does not support HTTPS. It doesn’t matter if the certificate is signed by a recognized CA or self-signed:
This was the last hurdle in my case, I had SSL enabled on my HA instance using the http integration. The workaround was to use a Nginx reverse proxy instead, so HA is reachable over both HTTP (only from the VLAN) and HTTPS.
Davidy, would you mind expanding on your setup, please? How exactly is that proxy setup? What do you use for external and internal URLs in the app? Do you use base_url in your config? I’m really interested in getting local fulfillment working. Thanks!
I can try. Some steps will be deliberately vague because they depend on the capabilities of the router, YMMV, so bear with me.
In my router, I have:
Configured dynamic DNS for my domain name provider, so that my HA URL points to my public IP, and the DNS record gets updated when my dynamic IP changes.
Configured DHCP to assign a static private IP to my HA instance.
Allowed mDNS on the IOT VLAN (and set mDNS repeater for any other VLANs where it is desired)
Set port forwardings from the public IP to the private IP of my HA instance, for TCP ports 443 (so HTTPS works) and 80 (so HTTP works, needed for Let’s Encrypt cert renewals), but not for port 8123, so HA is not directly reachable from outside without going through a proxy.
(optional but recommended): Configured DHCP to assign static private IPs to the Google devices as well. This allows setting up firewall rules to block all other unwanted IOT devices from reaching the private IP of HA on port 8123.
(probably optional but I haven’t tested without it): Hosted a private split horizon DNS server (mostly for ad blocking), and enabled hairpinning. With this, all traffic from within my LAN to either my HA URL or its public IP gets routed straight back to the private IP of my HA instance. This is tricky - if my router didn’t support this, I would look at a Pi Hole or some private DNS server to try and set it up.
In my HA instance, I have:
Removed the port and SSL fields from the http: integration in configuration.yaml, so HA listens as default, on its private IP and port 8123. Didn’t have base_url (IIRC it’s deprecated)
Both internal and external URLs set to the same: my HA URL, with https:// prefix, and no port (so it’s 443 by default). I believe this requires hairpinning -see above-, otherwise I would just leave both URLs unset, or set to http://[the-private-IP]:8123.
Installed the Nginx Proxy Manager addon, configured to respond to my HA URL, to force HTTPS with a Let’s Encrypt certificate, and to send all that traffic to the private IP of HA on port 8123.
With all this,
HTTPS requests from anywhere to my HA URL on port 443 go to the Nginx Proxy Manager and from there to HA on port 8123.
HTTP requests from anywhere to my HA URL on port 80 also go to the Nginx Proxy Manager, which forces them to HTTPS, leading to case 1 above.
HTTP requests from within the LAN to port 8123 can reach HA straight through - this is what allows Local Fulfillment to work.
HTTP requests from outside to port 8123 are blocked, as the router is not forwarding that port.
For cases 1-3, if you manage to get split-horizon DNS and hairpinning working, then internal traffic does not leave the LAN.
Thank you for your post, this was fantastic. I’ve made a good bit of progress, but I don’t think I’m quite there just yet. Here’s what I’ve done:
Moved my duckDNS setup to my Edgerouter Lite and deleted the duckDNS addon from HA, it looks to be doing well (from the ERL):
interface : eth0
ip address : 174.xxx.xxx.xxx
host-name : xxx
last update : Fri Feb 4 08:18:45 2022
update-status: good
I do the same with my DHCP server, using it to assign static IPs to most things in my network.
mDNS looks to be working on the network. When I use All My LAN:
I go to the mDNS Devices tab on the left, then click on _googlecast._tcb.local and all my google home minis show up. HA and my minis are all on the same network.
I ripped out the 8123 port forward on the ERL and setup 80>>80 TCP and 443>>443 TCP to the private IP of HA.
I’ve had Hairpin NAT in my ERL checked for a while, and I have had a static DNS entry in pihole for my xxx.duckdns.org domain to point to it’s private IP for a while too. DNS queries within my LAN for my xxx.duckdns.org domain are showing the private IP.
I left http: in the config, but removed ssl_certificate and ssl_key entries. Added use_x_forwarded_for and trusted_proxies entries cause of the Nginx Proxy Manager. Also left ip_ban_enabled and login_attempts_threshold in that section.
I initially tried https://xxx.duckdns.org in both the internal and external URLSs in the HA general settings. I was working on it super late last night so I don’t remember for sure why, but I changed the internal to http://.
Installed the Nginx Proxy Manager addon, have my xxx.duckdns.org domain setup for HTTP to the private HA IP and port 8123, websockets turned on, force SSL turned on and it got a new Let’s Encrypt cert.
So, for results:
ON LAN:
https://xxx.duckdns.org/ goes right to HA, browser shows as secure, but it's not the certificate I made yesterday
https://xxx.duckdns.org:8123 ERR_SSL_PROTOCOL_ERROR
http://xxx.duckdns.org/ redirects to https://xxx.duckdns.org/, browser shows as secure, but it's not the certificate I made yesterday
http://xxx.duckdns.org:8123 works, browser shows as not secure
http://LOCAL_HA_IP/ I get the Nginx congratulations page
http://LOCAL_HA_IP:8123 works, browser shows as not secure
https://LOCAL_HA_IP/ ERR_HTTP2_PROTOCOL_ERROR
https://LOCAL_HA_IP:8123 ERR_SSL_PROTOCOL_ERROR
ON WAN:
https://xxx.duckdns.org/ goes right to HA, browser shows secure, using the certificate issued yesterday
https://xxx.duckdns.org:8123 site can't be reached
http://xxx.duckdns.org/ to https://xxx.duckdns.org/, browser shows as secure, using the certificate issued yesterday
http://xxx.duckdns.org:8123 site can't be reached
So all of that sounds to me like what should be happening. But I’m still unsure of local fulfillment on Google assistant. I went through the local fulfillment setup, uploading those files and putting mDNS in there. I’ve made sure to remove the port from my HA authorization and token URLs in the google actions console webpage. I’ve rebooted HA, re-linked my [test] service in the google home app on my phone, and rebooted my google home mini. But every time I tell the google machine to do something it doesn’t show local like yours does. Thoughts?
My local instance runs on http…
Used nabu casa for remote https… Wasn’t working, no local commands…
Turned off nabucase, setup manuel edition with that .JS file…
Installed nginx, so remote url is https and local still http…
Still commands are not fired local…