Add full Pi 5 satellite setup with ReSpeaker 2-Mics pHAT for kitchen voice control via Wyoming protocol. Includes satellite_wrapper.py that monkey-patches WakeStreamingSatellite to fix three compounding bugs: - TTS echo suppression: mutes wake word detection while speaker plays - Server writer race fix: checks _writer before streaming, re-arms on None - Streaming timeout: auto-recovers after 30s if pipeline hangs - Error recovery: resets streaming state on server Error events Also includes Pi 5 hardware workarounds (wm8960 overlay, stereo-only audio wrappers, ALSA mixer calibration) and deploy.sh with fast iteration commands (--push-wrapper, --test-logs). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
160 lines
5.8 KiB
Bash
Executable File
160 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# homeai-rpi/deploy.sh — Deploy/manage Wyoming Satellite on Raspberry Pi from Mac Mini
|
|
#
|
|
# Usage:
|
|
# ./deploy.sh — full setup (push + install on Pi)
|
|
# ./deploy.sh --status — check satellite status
|
|
# ./deploy.sh --restart — restart satellite service
|
|
# ./deploy.sh --logs — tail satellite logs
|
|
# ./deploy.sh --test-audio — record 3s from mic, play back through speaker
|
|
# ./deploy.sh --update — update Python packages only
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# ─── Pi connection ──────────────────────────────────────────────────────────
|
|
|
|
PI_HOST="SELBINA.local"
|
|
PI_USER="aodhan"
|
|
PI_SSH="${PI_USER}@${PI_HOST}"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
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} $*"; exit 1; }
|
|
log_step() { echo -e "${CYAN}[STEP]${NC} $*"; }
|
|
|
|
# ─── SSH helpers ────────────────────────────────────────────────────────────
|
|
|
|
pi_ssh() {
|
|
ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new "${PI_SSH}" "$@"
|
|
}
|
|
|
|
pi_scp() {
|
|
scp -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new "$@"
|
|
}
|
|
|
|
check_connectivity() {
|
|
log_step "Checking connectivity to ${PI_HOST}..."
|
|
if ! ping -c 1 -t 3 "${PI_HOST}" &>/dev/null; then
|
|
log_error "Cannot reach ${PI_HOST}. Is the Pi on?"
|
|
fi
|
|
if ! pi_ssh "echo ok" &>/dev/null; then
|
|
log_error "SSH to ${PI_SSH} failed. Set up SSH keys:
|
|
ssh-copy-id ${PI_SSH}"
|
|
fi
|
|
log_ok "Connected to ${PI_HOST}"
|
|
}
|
|
|
|
# ─── Commands ───────────────────────────────────────────────────────────────
|
|
|
|
cmd_setup() {
|
|
check_connectivity
|
|
|
|
log_step "Pushing setup script to Pi..."
|
|
pi_scp "${SCRIPT_DIR}/setup.sh" "${PI_SSH}:~/homeai-satellite-setup.sh"
|
|
|
|
log_step "Running setup on Pi..."
|
|
pi_ssh "chmod +x ~/homeai-satellite-setup.sh && ~/homeai-satellite-setup.sh"
|
|
|
|
log_ok "Setup complete!"
|
|
}
|
|
|
|
cmd_status() {
|
|
check_connectivity
|
|
log_step "Satellite status:"
|
|
pi_ssh "systemctl status homeai-satellite.service --no-pager" || true
|
|
}
|
|
|
|
cmd_restart() {
|
|
check_connectivity
|
|
log_step "Restarting satellite..."
|
|
pi_ssh "sudo systemctl restart homeai-satellite.service"
|
|
sleep 2
|
|
pi_ssh "systemctl is-active homeai-satellite.service" && log_ok "Satellite running" || log_warn "Satellite not active"
|
|
}
|
|
|
|
cmd_logs() {
|
|
check_connectivity
|
|
log_info "Tailing satellite logs (Ctrl+C to stop)..."
|
|
pi_ssh "journalctl -u homeai-satellite.service -f --no-hostname"
|
|
}
|
|
|
|
cmd_test_audio() {
|
|
check_connectivity
|
|
log_step "Recording 3 seconds from mic..."
|
|
pi_ssh "arecord -D plughw:2,0 -d 3 -f S16_LE -r 16000 -c 1 /tmp/homeai-test.wav 2>/dev/null"
|
|
log_step "Playing back through speaker..."
|
|
pi_ssh "aplay -D plughw:2,0 /tmp/homeai-test.wav 2>/dev/null"
|
|
log_ok "Audio test complete. Did you hear yourself?"
|
|
}
|
|
|
|
cmd_update() {
|
|
check_connectivity
|
|
log_step "Updating Python packages on Pi..."
|
|
pi_ssh "source ~/homeai-satellite/venv/bin/activate && pip install --upgrade wyoming-satellite openwakeword -q"
|
|
|
|
log_step "Pushing latest scripts..."
|
|
pi_scp "${SCRIPT_DIR}/satellite_wrapper.py" "${PI_SSH}:~/homeai-satellite/satellite_wrapper.py"
|
|
pi_ssh "sudo systemctl restart homeai-satellite.service"
|
|
|
|
log_ok "Updated and restarted"
|
|
}
|
|
|
|
cmd_push_wrapper() {
|
|
check_connectivity
|
|
log_step "Pushing satellite_wrapper.py..."
|
|
pi_scp "${SCRIPT_DIR}/satellite_wrapper.py" "${PI_SSH}:~/homeai-satellite/satellite_wrapper.py"
|
|
log_step "Restarting satellite..."
|
|
pi_ssh "sudo systemctl restart homeai-satellite.service"
|
|
sleep 2
|
|
pi_ssh "systemctl is-active homeai-satellite.service" && log_ok "Satellite running" || log_warn "Satellite not active — check logs"
|
|
}
|
|
|
|
cmd_test_logs() {
|
|
check_connectivity
|
|
log_info "Filtered satellite logs — key events only (Ctrl+C to stop)..."
|
|
pi_ssh "journalctl -u homeai-satellite.service -f --no-hostname" \
|
|
| grep --line-buffered -iE \
|
|
'Waiting for wake|Streaming audio|transcript|synthesize|Speaker active|unmute|_writer|timeout|error|Error|Wake word detected|re-arming|resetting'
|
|
}
|
|
|
|
# ─── Main ───────────────────────────────────────────────────────────────────
|
|
|
|
case "${1:-}" in
|
|
--status) cmd_status ;;
|
|
--restart) cmd_restart ;;
|
|
--logs) cmd_logs ;;
|
|
--test-audio) cmd_test_audio ;;
|
|
--test-logs) cmd_test_logs ;;
|
|
--update) cmd_update ;;
|
|
--push-wrapper) cmd_push_wrapper ;;
|
|
--help|-h)
|
|
echo "Usage: $0 [command]"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " (none) Full setup — push and install satellite on Pi"
|
|
echo " --status Check satellite service status"
|
|
echo " --restart Restart satellite service"
|
|
echo " --logs Tail satellite logs (live, all)"
|
|
echo " --test-logs Tail filtered logs (key events only)"
|
|
echo " --test-audio Record 3s from mic, play back on speaker"
|
|
echo " --push-wrapper Push satellite_wrapper.py and restart (fast iteration)"
|
|
echo " --update Update packages and restart"
|
|
echo " --help Show this help"
|
|
echo ""
|
|
echo "Pi: ${PI_SSH} (${PI_HOST})"
|
|
;;
|
|
"") cmd_setup ;;
|
|
*) log_error "Unknown command: $1. Use --help for usage." ;;
|
|
esac
|