Living room unit fully working: on-device wake word (hey_jarvis), voice pipeline via HA (Wyoming STT → OpenClaw → Wyoming TTS), static PNG display states, OTA updates. Includes deploy.sh for quick OTA with custom image support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
178 lines
5.4 KiB
Bash
178 lines
5.4 KiB
Bash
#!/usr/bin/env bash
|
|
# homeai-esp32/setup.sh — P6: ESPHome firmware for ESP32-S3-BOX-3
|
|
#
|
|
# Usage:
|
|
# ./setup.sh — check environment + validate config
|
|
# ./setup.sh flash — compile + flash via USB (first time)
|
|
# ./setup.sh ota — compile + flash via OTA (wireless)
|
|
# ./setup.sh logs — stream device logs
|
|
# ./setup.sh validate — validate YAML without compiling
|
|
#
|
|
# Prerequisites:
|
|
# - ~/homeai-esphome-env — Python 3.12 venv with ESPHome
|
|
# - Home Assistant running on 10.0.0.199
|
|
# - Wyoming STT/TTS running on Mac Mini (ports 10300/10301)
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
ESPHOME_VENV="${HOME}/homeai-esphome-env"
|
|
ESPHOME="${ESPHOME_VENV}/bin/esphome"
|
|
ESPHOME_DIR="${SCRIPT_DIR}/esphome"
|
|
DEFAULT_CONFIG="${ESPHOME_DIR}/homeai-living-room.yaml"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
|
log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
|
|
|
# ─── Environment checks ──────────────────────────────────────────────────────
|
|
|
|
check_env() {
|
|
local ok=true
|
|
|
|
log_info "Checking environment..."
|
|
|
|
# ESPHome venv
|
|
if [[ -x "${ESPHOME}" ]]; then
|
|
local version
|
|
version=$("${ESPHOME}" version 2>/dev/null)
|
|
log_ok "ESPHome: ${version}"
|
|
else
|
|
log_error "ESPHome not found at ${ESPHOME}"
|
|
echo " Install: /opt/homebrew/opt/python@3.12/bin/python3.12 -m venv ${ESPHOME_VENV}"
|
|
echo " ${ESPHOME_VENV}/bin/pip install 'esphome>=2025.5.0'"
|
|
ok=false
|
|
fi
|
|
|
|
# secrets.yaml
|
|
if [[ -f "${ESPHOME_DIR}/secrets.yaml" ]]; then
|
|
if grep -q "YOUR_" "${ESPHOME_DIR}/secrets.yaml" 2>/dev/null; then
|
|
log_warn "secrets.yaml contains placeholder values — edit before flashing"
|
|
ok=false
|
|
else
|
|
log_ok "secrets.yaml configured"
|
|
fi
|
|
else
|
|
log_error "secrets.yaml not found at ${ESPHOME_DIR}/secrets.yaml"
|
|
ok=false
|
|
fi
|
|
|
|
# Config file
|
|
if [[ -f "${DEFAULT_CONFIG}" ]]; then
|
|
log_ok "Config: $(basename "${DEFAULT_CONFIG}")"
|
|
else
|
|
log_error "Config not found: ${DEFAULT_CONFIG}"
|
|
ok=false
|
|
fi
|
|
|
|
# Illustrations
|
|
local illust_dir="${ESPHOME_DIR}/illustrations"
|
|
local illust_count
|
|
illust_count=$(find "${illust_dir}" -name "*.png" 2>/dev/null | wc -l | tr -d ' ')
|
|
if [[ "${illust_count}" -ge 7 ]]; then
|
|
log_ok "Illustrations: ${illust_count} PNGs in illustrations/"
|
|
else
|
|
log_warn "Missing illustrations (found ${illust_count}, need 7)"
|
|
fi
|
|
|
|
# Wyoming services on Mac Mini
|
|
if curl -sf "http://localhost:10300" -o /dev/null 2>/dev/null || nc -z localhost 10300 2>/dev/null; then
|
|
log_ok "Wyoming STT (port 10300) reachable"
|
|
else
|
|
log_warn "Wyoming STT (port 10300) not reachable"
|
|
fi
|
|
|
|
if curl -sf "http://localhost:10301" -o /dev/null 2>/dev/null || nc -z localhost 10301 2>/dev/null; then
|
|
log_ok "Wyoming TTS (port 10301) reachable"
|
|
else
|
|
log_warn "Wyoming TTS (port 10301) not reachable"
|
|
fi
|
|
|
|
# Home Assistant
|
|
if curl -sk "https://10.0.0.199:8123" -o /dev/null 2>/dev/null; then
|
|
log_ok "Home Assistant (10.0.0.199:8123) reachable"
|
|
else
|
|
log_warn "Home Assistant not reachable — ESP32 won't be able to connect"
|
|
fi
|
|
|
|
if $ok; then
|
|
log_ok "Environment ready"
|
|
else
|
|
log_warn "Some issues found — fix before flashing"
|
|
fi
|
|
}
|
|
|
|
# ─── Commands ─────────────────────────────────────────────────────────────────
|
|
|
|
cmd_flash() {
|
|
local config="${1:-${DEFAULT_CONFIG}}"
|
|
log_info "Compiling + flashing via USB: $(basename "${config}")"
|
|
log_info "First compile downloads ESP-IDF toolchain (~500MB), takes 5-10 min..."
|
|
cd "${ESPHOME_DIR}"
|
|
"${ESPHOME}" run "$(basename "${config}")"
|
|
}
|
|
|
|
cmd_ota() {
|
|
local config="${1:-${DEFAULT_CONFIG}}"
|
|
log_info "Compiling + OTA upload: $(basename "${config}")"
|
|
cd "${ESPHOME_DIR}"
|
|
"${ESPHOME}" run "$(basename "${config}")"
|
|
}
|
|
|
|
cmd_logs() {
|
|
local config="${1:-${DEFAULT_CONFIG}}"
|
|
log_info "Streaming logs for: $(basename "${config}")"
|
|
cd "${ESPHOME_DIR}"
|
|
"${ESPHOME}" logs "$(basename "${config}")"
|
|
}
|
|
|
|
cmd_validate() {
|
|
local config="${1:-${DEFAULT_CONFIG}}"
|
|
log_info "Validating: $(basename "${config}")"
|
|
cd "${ESPHOME_DIR}"
|
|
"${ESPHOME}" config "$(basename "${config}")"
|
|
log_ok "Config valid"
|
|
}
|
|
|
|
# ─── Main ─────────────────────────────────────────────────────────────────────
|
|
|
|
case "${1:-}" in
|
|
flash)
|
|
check_env
|
|
echo ""
|
|
cmd_flash "${2:-}"
|
|
;;
|
|
ota)
|
|
check_env
|
|
echo ""
|
|
cmd_ota "${2:-}"
|
|
;;
|
|
logs)
|
|
cmd_logs "${2:-}"
|
|
;;
|
|
validate)
|
|
cmd_validate "${2:-}"
|
|
;;
|
|
*)
|
|
check_env
|
|
echo ""
|
|
echo "Usage: $0 {flash|ota|logs|validate} [config.yaml]"
|
|
echo ""
|
|
echo " flash Compile + flash via USB (first time)"
|
|
echo " ota Compile + flash via OTA (wireless, after first flash)"
|
|
echo " logs Stream device logs"
|
|
echo " validate Validate YAML config without compiling"
|
|
echo ""
|
|
echo "Default config: $(basename "${DEFAULT_CONFIG}")"
|
|
;;
|
|
esac
|