Skip to content

Home Assistant

99-hubz.rules

SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8a2a", ATTRS{serial}=="8130052B", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="zwave", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8a2a", ATTRS{serial}=="8130052B", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="zigbee", MODE="0666"

mosquitto.conf

allow_anonymous true
listener 1883
persistence true

Docker Compose Stack

---

###
# Home Automation
###

services:
  homeassistant:
    privileged: true
    image: "ghcr.io/home-assistant/home-assistant:stable"
    container_name: homeassistant
    restart: unless-stopped
    healthcheck:
      test: curl --fail http://localhost:8123 || exit 1
      retries: 3
      interval: 10s
      timeout: 5s
    environment:
      - TZ=America/Edmonton
      - PUID=1000
      - PGID=1000
      - UMASK=007
      - PACKAGES=iputils
    volumes:
      - /mnt/homeassistant:/config
      - ./homeassistant-run:/etc/services.d/home-assistant/run
      - /etc/localtime:/etc/localtime:ro
      - /mnt/homeassistant/media:/media
    #devices:
    #  - /dev/zigbee
    #  - /dev/zwave
    #network_mode: host
    ports:
      - 8123:8123

# esphome server
  esphome:
    image: ghcr.io/esphome/esphome
    container_name: esphome
    restart: unless-stopped
    depends_on:
      homeassistant:
        condition: service_healthy
    environment:
      - USERNAME=${USER-ESP}
      - PASSWORD=${PASS-ESP}
    volumes:
      - ./config:/config
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 6052:6052
    #devices:
    #  - /dev/ttyUSB2:/dev/usbDevice

# Text to speach
  piper:
    image: rhasspy/wyoming-piper
    container_name: piper
    restart: unless-stopped
    depends_on:
      homeassistant:
        condition: service_healthy
    command: --voice en_US-lessac-medium
    volumes:
      - /mnt/homeassistant/piper:/data
    ports:
      - 10200:10200

# Speach to text
  whisper:
    image: rhasspy/wyoming-whisper:latest
    container_name: whisper
    restart: unless-stopped
    depends_on:
      homeassistant:
        condition: service_healthy
    command: --model base --language en
    volumes:
     - /mnt/homeassistant/whisper:/data
    ports:
      - 10300:10300

# Wake word
  openwakeword:
    image: rhasspy/wyoming-openwakeword
    container_name: openwakeword
    restart: unless-stopped
    depends_on:
      - homeassistant
      - whisper
    command: --preload-model 'ok_nabu'
    volumes:
      - /mnt/homeassistant/openwakword:/data
    ports:
      - 10400:10400

HomeAssistant rootless script

homeassistant-run.sh
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash

USER="homeassistant"
GROUP="$USER"
PUID="${PUID:-1000}"
PGID="${PGID:-1000}"

UMASK="${UMASK:-}"

# If s6-applyuidgid is missing, install s6-ipcserver
REQUIRED_PACKAGES=""
type -t s6-applyuidgid >/dev/null || REQUIRED_PACKAGES="s6-ipcserver"

PACKAGES="${PACKAGES:-}"

VENV_PATH="${VENV:-/var/tmp/homeassistant-venv}"
CONFIG_PATH=/config

#
# Create user
#

# Some HA commands seem to fail if we don't have an actual user.
# ie: shell_command would return error code 255
bashio::log.info "Creating user $USER with $PUID:$PGID"

deluser "$USER" >/dev/null 2>&1 || true
delgroup "$GROUP" >/dev/null 2>&1 || true

# Re-use existing group (can't delgroup a group that is in use)
group="$(getent group "$PGID" | cut -d: -f1 || true)"
if [ -z "$group" ]; then
  addgroup -g "$PGID" "$GROUP"
else
  bashio::log.notice "Re-using existing group with gid $PGID: $group"
  GROUP="$group"
fi

# Replace existing user (ensures correct shell and primary group)
user="$(getent passwd "$PUID" | cut -d: -f1 || true)"
if [ -n "$user" ]; then
  bashio::log.notice "Replacing existing user with uid $PUID: $user"
  deluser "$user"
fi
adduser -G "$GROUP" -D -u "$PUID" "$USER"

if [ -n "${EXTRA_GID:-}" ]; then
  bashio::log.info "Resolving supplementary GIDs: $EXTRA_GID"
  supplementary_groups=()

  for gid in $EXTRA_GID; do
    group="$(getent group "$gid" | cut -d: -f1 || true)"

    if [ -z "$group" ]; then
      group="$USER-$gid"
      addgroup -g "$gid" "$group"
    fi

    supplementary_groups+=( "$group" )
  done

  bashio::log.info "Appending supplementary groups: ${supplementary_groups[*]}"
  for group in "${supplementary_groups[@]}"; do
    addgroup "$USER" "$group"
  done
fi
#
# Install extra packages
#

for package in $REQUIRED_PACKAGES $PACKAGES; do
  if ! apk info --quiet --installed -- "$package"; then
    bashio::log.info "Installing package: $package"
    apk add --quiet --no-progress --no-cache -- "$package"
  fi
done

#
# Create virtual environment
#

bashio::log.info "Initializing venv in $VENV_PATH"
su "$USER" \
  -c "python3 -m venv --system-site-packages '$VENV_PATH'"

#
# Fix permissions
#

if [ -n "${UMASK}" ]; then
  bashio::log.info "Setting umask: $UMASK"
  umask "$UMASK"
fi

#
# Run homeassistant
#

bashio::log.info "Activating venv"
# shellcheck source=/dev/null
. "$VENV_PATH/bin/activate"

bashio::log.info "Setting new \$HOME"
HOME="$( getent passwd "$USER" | cut -d: -f6 )"
export HOME

# Everything below should be kept in sync with upstream's
#   https://github.com/home-assistant/core/blob/dev/rootfs/etc/services.d/home-assistant/run
cd "$CONFIG_PATH" || bashio::exit.nok "Can't find config folder: $CONFIG_PATH"

# Enable Jemalloc for Home Assistant Core, unless disabled
if [[ -z "${DISABLE_JEMALLOC+x}" ]]; then
  export LD_PRELOAD="/usr/local/lib/libjemalloc.so.2"
fi

bashio::log.info "Starting homeassistant"
exec \
  s6-setuidgid "$USER" \
  python3 -m homeassistant --config "$CONFIG_PATH"