320 lines
11 KiB
Bash
Executable File
320 lines
11 KiB
Bash
Executable File
#!/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" <<EOF
|
|
homeassistant: true
|
|
permit_join: false
|
|
mqtt:
|
|
base_topic: zigbee2mqtt
|
|
server: 'mqtt://mosquitto:1883'
|
|
serial:
|
|
port: '/dev/ttyACM0'
|
|
adapter: zstack
|
|
advanced:
|
|
network_key: GENERATE
|
|
frontend:
|
|
port: 8080
|
|
EOF
|
|
echo " NOTE: adapter set to 'zstack' for your CC2652P (Haozee/Sonoff Dongle-P style) USB dongle."
|
|
echo " If Zigbee2MQTT fails to connect, it may need CC2652P coordinator firmware flashed first"
|
|
echo " (generic-branded gateways sometimes ship with non-coordinator firmware)."
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 6. Frigate config (placeholder — edit before first real use)
|
|
# ---------------------------------------------------------------------------
|
|
echo "--- Writing Frigate placeholder config ---"
|
|
cat > "$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" <<EOF
|
|
name: smart-home
|
|
|
|
services:
|
|
homeassistant:
|
|
image: ghcr.io/home-assistant/home-assistant:stable
|
|
container_name: homeassistant
|
|
restart: unless-stopped
|
|
privileged: true
|
|
network_mode: host
|
|
volumes:
|
|
- ${BASE_DIR}/homeassistant:/config
|
|
- /etc/localtime:/etc/localtime:ro
|
|
environment:
|
|
- TZ=${TIMEZONE}
|
|
|
|
mosquitto:
|
|
image: eclipse-mosquitto:2
|
|
container_name: mosquitto
|
|
restart: unless-stopped
|
|
ports:
|
|
- "1883:1883"
|
|
volumes:
|
|
- ${BASE_DIR}/mosquitto/config:/mosquitto/config
|
|
- ${BASE_DIR}/mosquitto/data:/mosquitto/data
|
|
- ${BASE_DIR}/mosquitto/log:/mosquitto/log
|
|
|
|
zigbee2mqtt:
|
|
image: koenkk/zigbee2mqtt:latest
|
|
container_name: zigbee2mqtt
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- mosquitto
|
|
ports:
|
|
- "8080:8080"
|
|
volumes:
|
|
- ${BASE_DIR}/zigbee2mqtt/data:/app/data
|
|
- /etc/localtime:/etc/localtime:ro
|
|
devices:
|
|
- ${ZIGBEE_USB_DEVICE}:/dev/ttyACM0
|
|
environment:
|
|
- TZ=${TIMEZONE}
|
|
|
|
frigate:
|
|
image: ghcr.io/blakeblackshear/frigate:stable
|
|
container_name: frigate
|
|
restart: unless-stopped
|
|
privileged: true
|
|
shm_size: "256mb"
|
|
depends_on:
|
|
- mosquitto
|
|
ports:
|
|
- "5000:5000"
|
|
- "8554:8554"
|
|
- "8555:8555/tcp"
|
|
- "8555:8555/udp"
|
|
volumes:
|
|
- ${BASE_DIR}/frigate/config:/config
|
|
- ${BASE_DIR}/frigate/media:/media/frigate
|
|
- /etc/localtime:/etc/localtime:ro
|
|
${FRIGATE_DEVICES}
|
|
environment:
|
|
- TZ=${TIMEZONE}
|
|
|
|
grocy:
|
|
image: lscr.io/linuxserver/grocy:latest
|
|
container_name: grocy
|
|
restart: unless-stopped
|
|
ports:
|
|
- "9283:80"
|
|
volumes:
|
|
- ${BASE_DIR}/grocy/config:/config
|
|
environment:
|
|
- PUID=1000
|
|
- PGID=1000
|
|
- TZ=${TIMEZONE}
|
|
${MEALIE_BLOCK}
|
|
EOF
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 8. Bring the stack up
|
|
# ---------------------------------------------------------------------------
|
|
echo "--- Starting containers ---"
|
|
cd "$BASE_DIR"
|
|
docker compose up -d
|
|
|
|
echo
|
|
echo "=== Done ==="
|
|
echo "Services should be reachable at:"
|
|
echo " Home Assistant : http://<host-ip>:8123"
|
|
echo " Zigbee2MQTT UI : http://<host-ip>:8080"
|
|
echo " Frigate : http://<host-ip>:5000"
|
|
echo " Grocy : http://<host-ip>:9283"
|
|
if [[ "$ENABLE_MEALIE" == "true" ]]; then
|
|
echo " Mealie : http://<host-ip>: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."
|