After installing Rhasspy on a Raspberry Pi 3B and seeing it struggle, I decided to move everything to a beefier Jetson Nano. While I was at it, took the opportunity to switch to docker to avoid some of the systemd wrangling.

Rhasspy

Rhasspy provides speech recognition, speech-to-intent, and text-to-speech. Installation is mostly the same as before:

docker run -d -p 12101:12101 \
      --name rhasspy \
      --restart unless-stopped \
      -v "$HOME/.config/rhasspy/profiles:/profiles" \
      --device /dev/snd:/dev/snd \
      --device /dev/bus/usb:/dev/bus/usb \
      synesthesiam/rhasspy-server:latest \
      --user-profiles /profiles \
      --profile en

With the Nano, I needed to add --device /dev/bus/usb:/dev/bus/usb so USB devices like ReSpeaker are also accessible inside the container.

Home Assistant

Home Assistant (Hass) is the “smart home” platform and among other things provides: intent handling, automation, location-based services, etc. Hass has docker installation instructions:

docker run --init -d --name="home-assistant" -e "TZ=America/New_York" -v /PATH_TO_YOUR_CONFIG:/config --net=host homeassistant/home-assistant:stable

We’ll change this to:

docker run -d -p 8123:8123 \
    --name hass \
    --restart unless-stopped \
    -v $HOME/.homeassistant:/config \
    -e "TZ=Asia/Nicosia" \
    homeassistant/home-assistant:stable
  • Shorten the name to “hass”, just because typing “home-assistant” is tedious
  • unless-stopped restart policy- the docker daemon will automatically (re-)start it
  • $HOME/.homeassistant like when doing manual install
  • Value after TZ= with the appropriate name from “tz database” time zones
  • host networking on Linux means we don’t need to forward any ports for the frontend like -p 8123:8123, but doesn’t seem to work with docker network (see below)

Integration

Both Hass and Rhasspy are running in containers, but they can’t talk to eachother yet. The “old” way to connect two containers was to use --link. The new way is using “networks”. First, create a network called “smart-home”:

docker network create smart-home

To each of the docker run commands we then add --network smart-home. For Hass, we also remove --net=host and add -p 8123:8123 (for the web frontend). Restart the containers and we can confirm that Rhasspy can talk to the “hass” container:

docker exec -it rhasspy bash
# Install ping (or some other command)
apt install -y inetutils-ping
ping hass

Now, when connecting Rhasspy to Hass, for Hass URL use http://hass:8123.

Start-Up

With everything on docker we don’t really need systemd to start the individual services, just the docker daemon itself.

We supply both our containers with --restart unless-stopped so the daemon will launch them as soon as it starts (unless we manually stop them). We just need to make sure the docker daemon starts at boot:

sudo systemctl enable docker
sudo reboot

# Wait for it to reboot

ssh jetson-nano.local
# Try Rhasspy TTS to make sure Rhasspy is running:
curl -X POST -d "hello world" http://localhost:12101/api/text-to-speech

And docker ps should output something similar to:

CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS              PORTS                      NAMES
e797909decb6        synesthesiam/rhasspy-server:latest    "/run.sh --user-prof…"   32 hours ago        Up About a minute   0.0.0.0:12101->12101/tcp   rhasspy
06cf50964e98        homeassistant/home-assistant:stable   "/bin/entry.sh pytho…"   33 hours ago        Up About a minute   0.0.0.0:8123->8123/tcp     hass

Be careful about using docker ps to verify everything is starting at boot. If the daemon didn’t start, docker ps will start it- along with the containers.

docker-compose

With multiple containers and so many options things are starting to get hairy. We can reign things in with docker compose. Create docker-compose.yml with mostly the same contents as the docker run commands:

version: '3'
services:
    hass:
        image: "homeassistant/home-assistant:stable"
        restart: unless-stopped
        volumes:
            - "$HOME/.homeassistant:/config"
        ports:
            - "8123:8123"
        environment:
            - TZ=Asia/Nicosia
    rhasspy:
        image: "synesthesiam/rhasspy-server:latest"
        restart: unless-stopped
        volumes:
            - "$HOME/.config/rhasspy/profiles:/profiles"
        ports:
            - "12101:12101"
        devices:
            - "/dev/snd:/dev/snd"
            - "/dev/bus/usb:/dev/bus/usb"
        command: --user-profiles /profiles --profile en

We don’t need the --network option because the desired networking is implicitly provided by compose.

Install docker compose and launch our containers:

# Install pre-requisites
sudo apt install -y python-pip libffi-dev libssl-dev
# Install docker-compose
sudo pip install docker-compose
# Start containers. `-d` for detached mode
docker-compose up -d

If you check Rhasspy, you may see the following problem:

HomeAssistantIntentHandler	Can't contact server	Unable to reach your Home Assistant server at http://hass:8123. Is it running?

Rhasspy starts before Hass is ready and listening. If you test further you’ll find that it has already retried and connected. This behavior aligns with the “docker ethos” of fault-tolerant containers. Should it really bother you, feel free to investigate the rickety world of container dependencies:

  • https://docs.docker.com/compose/startup-order/ and depends-on
  • SO #1, #2