#!/usr/bin/env bash # # Smart Home Container Host Setup # Target: Debian 12 (Bookworm) or Raspberry Pi OS Lite (Bookworm-based) # # Sets up Docker + a compose stack for: # - Home Assistant (Container install) # - Mosquitto (MQTT broker) # - Zigbee2MQTT (talks to your network-attached SLZB-06 coordinator) # - Frigate (NVR + face recognition, for the peephole cam) # - Grocy (self-hosted inventory / shopping list) # # Run as: sudo ./setup-smart-home-host.sh # # EDIT THE VARIABLES BELOW BEFORE RUNNING. set -euo pipefail # --------------------------------------------------------------------------- # CONFIGURATION — edit these before running # --------------------------------------------------------------------------- BASE_DIR="/opt/smart-home" # Where all container config/data will live TIMEZONE="Europe/Vienna" # Adjust to your timezone ENABLE_MEALIE="false" # Set to "true" to also deploy Mealie ENABLE_INTEL_HWACCEL="false" # Set to "true" if this host has an Intel iGPU for Frigate # --- Zigbee adapter: USB (CC2652P/CH340C, e.g. Haozee/Sonoff Dongle-P style) --- # Run `ls -l /dev/serial/by-id/` AFTER plugging the adapter in, and paste the # full path it shows here. This is more stable across reboots than /dev/ttyUSB0. # Example: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 ZIGBEE_USB_DEVICE="/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0" # --------------------------------------------------------------------------- # Sanity checks # --------------------------------------------------------------------------- if [[ $EUID -ne 0 ]]; then echo "Please run as root (sudo ./setup-smart-home-host.sh)" >&2 exit 1 fi if ! grep -qi "debian" /etc/os-release; then echo "Warning: this script targets Debian/Raspberry Pi OS. Proceeding anyway..." fi if [[ ! -e "$ZIGBEE_USB_DEVICE" ]]; then echo "Warning: $ZIGBEE_USB_DEVICE does not exist yet." echo " Plug in your Zigbee adapter and run 'ls -l /dev/serial/by-id/' to find the correct path," echo " then edit ZIGBEE_USB_DEVICE at the top of this script before re-running." echo " Continuing anyway — the zigbee2mqtt container just won't start correctly until this is fixed." fi echo "=== Smart Home Container Host Setup ===" echo "Base directory: $BASE_DIR" echo "Timezone: $TIMEZONE" echo "Zigbee adapter (USB): ${ZIGBEE_USB_DEVICE}" echo # --------------------------------------------------------------------------- # 1. System update + prerequisites # --------------------------------------------------------------------------- echo "--- Updating system and installing prerequisites ---" apt-get update apt-get upgrade -y apt-get install -y \ ca-certificates \ curl \ gnupg \ lsb-release \ jq # --------------------------------------------------------------------------- # 2. Install Docker Engine + Compose plugin (official Docker repo) # --------------------------------------------------------------------------- if ! command -v docker &> /dev/null; then echo "--- Installing Docker Engine ---" install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc ARCH="$(dpkg --print-architecture)" CODENAME="$(. /etc/os-release && echo "$VERSION_CODENAME")" echo \ "deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian ${CODENAME} stable" \ > /etc/apt/sources.list.d/docker.list apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Allow the invoking (non-root) user to run docker without sudo, if applicable if [[ -n "${SUDO_USER:-}" ]]; then usermod -aG docker "$SUDO_USER" echo "Added $SUDO_USER to the docker group. Log out/in for it to take effect." fi else echo "--- Docker already installed, skipping ---" fi # --------------------------------------------------------------------------- # 3. Directory structure # --------------------------------------------------------------------------- echo "--- Creating directory structure under $BASE_DIR ---" mkdir -p "$BASE_DIR"/{homeassistant,mosquitto/config,mosquitto/data,mosquitto/log,zigbee2mqtt/data,frigate/config,frigate/media,grocy/config,grocy/data} if [[ "$ENABLE_MEALIE" == "true" ]]; then mkdir -p "$BASE_DIR"/mealie/data fi # --------------------------------------------------------------------------- # 4. Mosquitto config # --------------------------------------------------------------------------- echo "--- Writing Mosquitto config ---" cat > "$BASE_DIR/mosquitto/config/mosquitto.conf" <<'EOF' # Basic internal-network broker config. # This trusts anything on your Docker/LAN network. If Mosquitto will ever be # reachable beyond your trusted LAN, add password_file auth before exposing it. listener 1883 allow_anonymous true persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log EOF # --------------------------------------------------------------------------- # 5. Zigbee2MQTT config (pre-seeded for the SLZB-06 network coordinator) # --------------------------------------------------------------------------- echo "--- Writing Zigbee2MQTT config ---" cat > "$BASE_DIR/zigbee2mqtt/data/configuration.yaml" < "$BASE_DIR/frigate/config/config.yml" <<'EOF' mqtt: host: mosquitto port: 1883 # Face recognition (Frigate 0.16+) face_recognition: enabled: true cameras: peephole: ffmpeg: inputs: - path: rtsp://USERNAME:PASSWORD@CAMERA_IP:554/STREAM_PATH roles: - detect - record detect: width: 1280 height: 720 fps: 5 record: enabled: true # Uncomment and adjust if using Intel QuickSync/OpenVINO hardware acceleration: # ffmpeg: # hwaccel_args: preset-vaapi # detectors: # ov: # type: openvino # device: GPU EOF echo " NOTE: edit $BASE_DIR/frigate/config/config.yml with your real camera RTSP URL before starting Frigate." # --------------------------------------------------------------------------- # 7. docker-compose.yml # --------------------------------------------------------------------------- echo "--- Writing docker-compose.yml ---" FRIGATE_DEVICES="" if [[ "$ENABLE_INTEL_HWACCEL" == "true" ]]; then FRIGATE_DEVICES=" devices: - /dev/dri:/dev/dri" fi MEALIE_BLOCK="" if [[ "$ENABLE_MEALIE" == "true" ]]; then MEALIE_BLOCK=" mealie: image: ghcr.io/mealie-recipes/mealie:latest container_name: mealie restart: unless-stopped ports: - \"9925:9000\" volumes: - ${BASE_DIR}/mealie/data:/app/data environment: - TZ=${TIMEZONE} - ALLOW_SIGNUP=false " fi cat > "$BASE_DIR/docker-compose.yml" <:8123" echo " Zigbee2MQTT UI : http://:8080" echo " Frigate : http://:5000" echo " Grocy : http://:9283" if [[ "$ENABLE_MEALIE" == "true" ]]; then echo " Mealie : http://:9925" fi echo echo "Next steps:" echo " 1. Edit $BASE_DIR/frigate/config/config.yml with your real peephole camera RTSP URL, then:" echo " docker compose -f $BASE_DIR/docker-compose.yml restart frigate" echo " 2. Check 'docker logs zigbee2mqtt' — if it can't open the serial port, confirm" echo " ZIGBEE_USB_DEVICE at the top of this script matches 'ls -l /dev/serial/by-id/'," echo " and that the dongle has Z-Stack coordinator firmware (not stock gateway firmware)." echo " 3. Complete Home Assistant's onboarding wizard at :8123." echo " 4. In HA, add the MQTT integration (it should auto-discover Zigbee2MQTT devices)." echo " 5. Add the CalDAV integration pointing at your Nextcloud instance." echo " 6. Point HA's Ollama conversation integration at your separate GPU/LLM host." echo echo "Updating later: cd $BASE_DIR && docker compose pull && docker compose up -d" echo "Backing up: stop the stack (docker compose down), then tar/copy $BASE_DIR, then start it again."