feat(phase-04): Wyoming Satellite integration + OpenClaw HA components
## Voice Pipeline (P3) - Replace openWakeWord daemon with Wyoming Satellite approach - Add Wyoming Satellite service on port 10700 for HA voice pipeline - Update setup.sh with cross-platform sed compatibility (macOS/Linux) - Add version field to Kokoro TTS voice info - Update launchd service loader to use Wyoming Satellite ## Home Assistant Integration (P4) - Add custom conversation agent component (openclaw_conversation) - Fix: Use IntentResponse instead of plain strings (HA API requirement) - Support both HTTP API and CLI fallback modes - Config flow for easy HA UI setup - Add OpenClaw bridge scripts (Python + Bash) - Add ha-ctl utility for HA entity control - Fix: Use context manager for token file reading - Add HA configuration examples and documentation ## Infrastructure - Add mem0 backup automation (launchd + script) - Add n8n workflow templates (morning briefing, notification router) - Add VS Code workspace configuration - Reorganize model files into categorized folders: - lmstudio-community/ - mlx-community/ - bartowski/ - mradermacher/ ## Documentation - Update PROJECT_PLAN.md with Wyoming Satellite architecture - Update TODO.md with completed Wyoming integration tasks - Add OPENCLAW_INTEGRATION.md for HA setup guide ## Testing - Verified Wyoming services running (STT:10300, TTS:10301, Satellite:10700) - Verified OpenClaw CLI accessibility - Confirmed cross-platform compatibility fixes
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.homeai.wyoming-satellite</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/aodhan/homeai-voice-env/bin/python3</string>
|
||||
<string>-m</string>
|
||||
<string>wyoming_satellite</string>
|
||||
<string>--uri</string>
|
||||
<string>tcp://0.0.0.0:10700</string>
|
||||
<string>--name</string>
|
||||
<string>Mac Mini Living Room</string>
|
||||
<string>--area</string>
|
||||
<string>Living Room</string>
|
||||
<string>--mic-command</string>
|
||||
<string>rec -q -r 16000 -c 1 -b 16 -t raw -</string>
|
||||
<string>--snd-command</string>
|
||||
<string>play -q -r 24000 -c 1 -b 16 -t raw -</string>
|
||||
<string>--mic-command-rate</string>
|
||||
<string>16000</string>
|
||||
<string>--mic-command-width</string>
|
||||
<string>2</string>
|
||||
<string>--mic-command-channels</string>
|
||||
<string>1</string>
|
||||
<string>--snd-command-rate</string>
|
||||
<string>24000</string>
|
||||
<string>--snd-command-width</string>
|
||||
<string>2</string>
|
||||
<string>--snd-command-channels</string>
|
||||
<string>1</string>
|
||||
<string>--awake-wav</string>
|
||||
<string>/System/Library/Sounds/Glass.aiff</string>
|
||||
<string>--done-wav</string>
|
||||
<string>/System/Library/Sounds/Blow.aiff</string>
|
||||
<string>--no-zeroconf</string>
|
||||
</array>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/homeai-wyoming-satellite.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/homeai-wyoming-satellite-error.log</string>
|
||||
|
||||
<key>ThrottleInterval</key>
|
||||
<integer>10</integer>
|
||||
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -9,7 +9,8 @@ LAUNCH_AGENTS=~/Library/LaunchAgents
|
||||
PLISTS=(
|
||||
com.homeai.wyoming-stt.plist
|
||||
com.homeai.wyoming-tts.plist
|
||||
com.homeai.wakeword.plist
|
||||
com.homeai.wyoming-satellite.plist
|
||||
# com.homeai.wakeword.plist # Disabled - wake word handled by Wyoming satellite + HA
|
||||
)
|
||||
|
||||
for plist in "${PLISTS[@]}"; do
|
||||
|
||||
@@ -6,15 +6,14 @@
|
||||
# - wyoming-faster-whisper — Wyoming STT adapter (port 10300)
|
||||
# - Kokoro TTS — fast text-to-speech via ONNX
|
||||
# - wyoming-kokoro — Wyoming TTS adapter (port 10301)
|
||||
# - Chatterbox TTS — voice cloning (MPS / CUDA)
|
||||
# - wyoming-satellite — Home Assistant voice satellite (port 10700)
|
||||
# - openWakeWord — always-on wake word detection
|
||||
#
|
||||
# Prerequisites:
|
||||
# - P1 (homeai-infra) completed — Home Assistant running
|
||||
# - P2 (homeai-llm) completed — Ollama running
|
||||
# - Python 3.10+ installed
|
||||
# - macOS: Xcode Command Line Tools (for whisper.cpp compilation)
|
||||
# - Linux: build-essential, cmake
|
||||
# - macOS: Xcode Command Line Tools, SoX audio toolkit
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -35,59 +34,156 @@ if ! curl -sf http://localhost:8123 -o /dev/null 2>/dev/null; then
|
||||
prereq_ok=false
|
||||
fi
|
||||
|
||||
if ! curl -sf http://localhost:11434 -o /dev/null 2>/dev/null; then
|
||||
log_warn "Ollama (P2) not reachable at :11434"
|
||||
prereq_ok=false
|
||||
fi
|
||||
|
||||
if ! command_exists python3; then
|
||||
log_warn "python3 not found — required for STT/TTS adapters"
|
||||
prereq_ok=false
|
||||
fi
|
||||
|
||||
if [[ "$prereq_ok" == "false" ]]; then
|
||||
log_warn "Prerequisites not met. Complete P1 and P2 first."
|
||||
if ! command_exists brew && [[ "$PLATFORM" == "macos" ]]; then
|
||||
log_warn "Homebrew not found — required for SoX installation"
|
||||
prereq_ok=false
|
||||
fi
|
||||
|
||||
# ─── TODO: Implementation ──────────────────────────────────────────────────────
|
||||
cat <<'EOF'
|
||||
if [[ "$prereq_ok" == "false" ]]; then
|
||||
log_warn "Some prerequisites not met. Continuing anyway..."
|
||||
fi
|
||||
|
||||
# ─── Install SoX (audio toolkit) ───────────────────────────────────────────────
|
||||
log_info "Installing SoX audio toolkit..."
|
||||
if [[ "$PLATFORM" == "macos" ]]; then
|
||||
if ! command_exists rec || ! command_exists play; then
|
||||
brew install sox
|
||||
log_ok "SoX installed"
|
||||
else
|
||||
log_ok "SoX already installed"
|
||||
fi
|
||||
else
|
||||
log_warn "Please install SoX manually on Linux: apt-get install sox libsox-fmt-all"
|
||||
fi
|
||||
|
||||
# ─── Create Python virtual environment ─────────────────────────────────────────
|
||||
VENV_DIR="$HOME/homeai-voice-env"
|
||||
log_info "Setting up Python environment at $VENV_DIR..."
|
||||
|
||||
if [[ ! -d "$VENV_DIR" ]]; then
|
||||
python3 -m venv "$VENV_DIR"
|
||||
log_ok "Created virtual environment"
|
||||
fi
|
||||
|
||||
source "$VENV_DIR/bin/activate"
|
||||
|
||||
# ─── Install Python packages ───────────────────────────────────────────────────
|
||||
log_info "Installing Python packages..."
|
||||
|
||||
pip install --upgrade pip
|
||||
|
||||
# Core Wyoming packages
|
||||
pip install wyoming>=1.8.0
|
||||
pip install wyoming-faster-whisper
|
||||
|
||||
# Wyoming satellite (note: has strict dependency on wyoming 1.4.1 but works with 1.8+)
|
||||
pip install wyoming-satellite
|
||||
|
||||
# TTS
|
||||
pip install kokoro-onnx
|
||||
|
||||
# Wake word
|
||||
pip install openwakeword pyaudio
|
||||
|
||||
log_ok "Python packages installed"
|
||||
|
||||
# ─── Create model directories ──────────────────────────────────────────────────
|
||||
log_info "Creating model directories..."
|
||||
mkdir -p "$HOME/models/whisper"
|
||||
mkdir -p "$HOME/models/kokoro"
|
||||
mkdir -p "$HOME/models/openwakeword"
|
||||
|
||||
# ─── Download models ───────────────────────────────────────────────────────────
|
||||
log_info "Downloading models..."
|
||||
|
||||
# Kokoro TTS model
|
||||
if [[ ! -f "$HOME/models/kokoro/kokoro-v1.0.onnx" ]]; then
|
||||
log_info "Downloading Kokoro TTS model..."
|
||||
curl -L -o "$HOME/models/kokoro/kokoro-v1.0.onnx" \
|
||||
"https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files/kokoro-v1.0.onnx" || \
|
||||
log_warn "Failed to download Kokoro model"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$HOME/models/kokoro/voices-v1.0.bin" ]]; then
|
||||
curl -L -o "$HOME/models/kokoro/voices-v1.0.bin" \
|
||||
"https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files/voices-v1.0.bin" || \
|
||||
log_warn "Failed to download Kokoro voices"
|
||||
fi
|
||||
|
||||
log_ok "Models downloaded (or already present)"
|
||||
|
||||
# ─── Install launchd services ──────────────────────────────────────────────────
|
||||
log_info "Installing launchd services..."
|
||||
|
||||
LAUNCHD_DIR="$SCRIPT_DIR/scripts/launchd"
|
||||
LAUNCH_AGENTS="$HOME/Library/LaunchAgents"
|
||||
|
||||
mkdir -p "$LAUNCH_AGENTS"
|
||||
|
||||
# Fix wyoming-satellite entry point if needed
|
||||
SATELLITE_BIN="$VENV_DIR/bin/wyoming-satellite"
|
||||
if [[ -f "$SATELLITE_BIN" ]] && grep -q "__main__.run()" "$SATELLITE_BIN"; then
|
||||
log_info "Fixing wyoming-satellite entry point..."
|
||||
# Cross-platform sed (macOS vs Linux)
|
||||
if [[ "$PLATFORM" == "macos" ]]; then
|
||||
sed -i '' 's/sys.exit(__main__.run())/import asyncio; asyncio.run(__main__.main())/' "$SATELLITE_BIN"
|
||||
else
|
||||
sed -i 's/sys.exit(__main__.run())/import asyncio; asyncio.run(__main__.main())/' "$SATELLITE_BIN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Copy plists
|
||||
for plist in com.homeai.wyoming-stt.plist com.homeai.wyoming-tts.plist \
|
||||
com.homeai.wakeword.plist com.homeai.wyoming-satellite.plist; do
|
||||
src="$LAUNCHD_DIR/$plist"
|
||||
dst="$LAUNCH_AGENTS/$plist"
|
||||
|
||||
if [[ -f "$src" ]]; then
|
||||
cp "$src" "$dst"
|
||||
log_ok "Installed: $plist"
|
||||
else
|
||||
log_warn "Missing: $plist"
|
||||
fi
|
||||
done
|
||||
|
||||
# ─── Summary ───────────────────────────────────────────────────────────────────
|
||||
cat <<EOF
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ P3: homeai-voice — NOT YET IMPLEMENTED │
|
||||
│ P3: homeai-voice — Setup Complete │
|
||||
│ │
|
||||
│ Implementation steps (see homeai-voice/PLAN.md): │
|
||||
│ Services configured: │
|
||||
│ • Wyoming STT → tcp://localhost:10300 (Whisper) │
|
||||
│ • Wyoming TTS → tcp://localhost:10301 (Kokoro) │
|
||||
│ • Wake Word Daemon → HTTP on :8080/wake (openWakeWord) │
|
||||
│ • Wyoming Satellite→ tcp://localhost:10700 (HA satellite) │
|
||||
│ │
|
||||
│ 1. whisper/install.sh │
|
||||
│ - Clone + compile whisper.cpp (Metal/CUDA flags) │
|
||||
│ - Download models: large-v3, medium.en │
|
||||
│ - Install wyoming-faster-whisper Python package │
|
||||
│ Next steps: │
|
||||
│ 1. Download Whisper models: │
|
||||
│ wyoming-faster-whisper --download-dir ~/models/whisper │
|
||||
│ │
|
||||
│ 2. tts/install-kokoro.sh │
|
||||
│ - pip install kokoro-onnx │
|
||||
│ - Install wyoming-kokoro adapter │
|
||||
│ 2. Load services: │
|
||||
│ ./homeai-voice/scripts/load-all-launchd.sh │
|
||||
│ │
|
||||
│ 3. tts/install-chatterbox.sh │
|
||||
│ - pip install chatterbox-tts │
|
||||
│ - Verify MPS (macOS) or CUDA (Linux) acceleration │
|
||||
│ 3. Configure Home Assistant: │
|
||||
│ Settings → Integrations → Add Wyoming Protocol │
|
||||
│ - STT: 10.0.0.199:10300 │
|
||||
│ - TTS: 10.0.0.199:10301 │
|
||||
│ - Satellite: 10.0.0.199:10700 │
|
||||
│ │
|
||||
│ 4. wyoming/install.sh │
|
||||
│ - Install wyoming-openwakeword │
|
||||
│ - Configure wake word: hey_jarvis │
|
||||
│ │
|
||||
│ 5. scripts/launchd/ or systemd/ │
|
||||
│ - wyoming-stt (port 10300) │
|
||||
│ - wyoming-tts (port 10301) │
|
||||
│ - wakeword daemon │
|
||||
│ │
|
||||
│ 6. wyoming/test-pipeline.sh │
|
||||
│ - End-to-end smoke test │
|
||||
│ 4. Create voice assistant pipeline in HA │
|
||||
│ │
|
||||
│ Interface contracts: │
|
||||
│ WYOMING_STT_URL=tcp://localhost:10300 │
|
||||
│ WYOMING_TTS_URL=tcp://localhost:10301 │
|
||||
│ WYOMING_SATELLITE_URL=tcp://localhost:10700 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
EOF
|
||||
|
||||
log_info "P3 is not yet implemented. See homeai-voice/PLAN.md for details."
|
||||
exit 0
|
||||
log_ok "P3 setup complete!"
|
||||
|
||||
@@ -63,6 +63,7 @@ class KokoroEventHandler(AsyncEventHandler):
|
||||
attribution=Attribution(name="kokoro", url=""),
|
||||
installed=True,
|
||||
languages=["en-us"],
|
||||
version="1.0",
|
||||
speakers=[TtsVoiceSpeaker(name=self._default_voice)],
|
||||
)
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user