Bluetooth TTS with HomeAssistant

I have been running HomeAssistant in our apartment for quite a while now. It is pretty well integrated and can adjust the lights, detect presence in all rooms and monitors temperature and humidity. One feature that I’ve been meaning to add for quite a while now is voice feedback using Text To Speech. HomeAssistant is running on my server in the livingroom that doesn’t have any speakers nearby. Ideally, the sound output should go through the Echo Dot but the API currently doesn’t support output besides what the Alexa Skills provide.

Thankfully, it is possible to connect to the Dot using Bluetooth for audio playback. Unfortunately, the setup on the server side wasn’t all that easy which is why I’m writing up the steps that I collected from various sources. This should work for a HomeAssistant installation on a Ubuntu 17.10 machine and assumes that HomeAssistant is already configured properly.

First, we’ll want to install the dependencies:

sudo apt install pulseaudio pulseaudio-module-bluetooth vlc bluez bluez-tools

Pulseaudio

Since I’m running the server headless, there are no X-sessions and therefore pulseaudio will not be started for the login user. Instead, we can run pulseaudio in system mode. To do so, we need to create the necessary users and groups.

addgroup --system pulse
adduser --system --ingroup pulse --home /var/run/pulse pulse
addgroup --system pulse-access
adduser pulse audio

adduser homeassistant pulse-access

The last line allows the homeassistant user to access the audio devices.

Now we can create a systemd service file /etc/systemd/system/pulseaudio.service with the following content:

[Unit]
Description=PulseAudio system server

[Service]
Type=notify
ExecStart=/usr/bin/pulseaudio --daemonize=no --system --realtime --log-target=journal

[Install]
WantedBy=multi-user.target

Since we want to allow pulseaudio to access bluetooth devices, we have to add some d-bus rules in /etc/dbus-1/system.d/pulse.conf:

<!DOCTYPE busconfig PUBLIC
 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
	<policy user="root">
		<allow own="org.pulseaudio.Server"/>
                <allow send_destination="org.bluez"/>
                <allow send_interface="org.bluez.Manager"/>
	</policy>
	<policy user="pulse">
		<allow own="org.pulseaudio.Server"/>
                <allow send_destination="org.bluez"/>
                <allow send_interface="org.bluez.Manager"/>
	</policy>
	<policy context="default">
                <deny own="org.pulseaudio.Server"/>
                <deny send_destination="org.bluez"/>
                <deny send_interface="org.bluez.Manager"/>
        </policy>
</busconfig>

Last but not least, we need to tell pulseaudio to always load the relevant bluetooth modules. This can be done by adding the following lines in /etc/pulse/system.pa:

### Automatically load driver modules for Bluetooth hardware
.ifexists module-bluetooth-policy.so
  load-module module-bluetooth-policy
.endif
.ifexists module-bluetooth-discover.so
  load-module module-bluetooth-discover
.endif

Finally, we can enable and start the service:

systemctl --system enable pulseaudio.service
systemctl --system start pulseaudio.service

Bluetooth

Now we need to make sure that Bluetooth is enabled and running:

systemctl --system enable bluetooth.service
systemctl --system start bluetooth.service

Then we can pair the Echo Dot. This is done by using the command bluetoothctl.

sudo bluetoothctl
[bluetooth]# discoverable on
Changing discoverable on succeeded
[bluetooth]# pairable on
Changing pairable on succeeded
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent 
Default agent request successful

Now, the server should be visible to the Echo Dot under its hostname. Pairing can be initiated through the Alexa app. During the pairing, there might be a request for confirmation. Afterwords, bluetoothctl can be quit.

At this point, everything should already be working. We can test this by adding the following lines in the HomeAssistant configuration:

media_player:
  - platform: vlc

tts:
  - platform: google

We can the go to the web interface and in the service call section call the service tts.google_say with the following parameters:

{"entity_id":"media_player.vlc","message":"Hello"}

This should cause HomeAssistant to request a TTS audio file from the Google TTS service. The file is then passed on to VLC which will play the file through the default pulseaudio device which is the bluetooth device.

Startup Configuration

This setup will continue to work as long as the server isn’t rebooted or the connection drops. In order to ensure that the bluetooth device is always connected, we can add a small daemon that repeatedly verifies that the device is connected and otherwise connects it. To do so, we create the script /usr/local/bin/echo-watchdog.sh (Fill in your Echo Dot’s MAC address):

#!/bin/bash

MAC="XX:XX:XX:XX:XX:XX"

while :
do
        if ! [[ $(hcitool con | grep $MAC) ]]; then
                echo "Echo is not yet connected"
                echo -e "connect $MAC\nquit\n" | bluetoothctl
        fi
        sleep 1
done
chmod +x /usr/local/bin/echo-watchdog.sh

And then we can create a systemd service file /etc/systemd/system/echo-watchdog.service for it:

[Unit]
After=bluetooth.service

[Service]
ExecStart=/usr/local/bin/echo-watchdog.sh

[Install]
WantedBy=default.target

By enabling and starting it, we make sure that the server always tries to connect the Echo Dot when it is available:

systemctl --system enable echo-watchdog.service
systemctl --system start echo-watchdog.service

Now everything is up and running and TTS can be integrated into the HomeAssistant scripts.

Sources