Files
Aodhan Collins 6a0bae2a0b 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
2026-03-08 02:06:37 +00:00

99 lines
2.6 KiB
Python

"""OpenClaw Conversation integration for Home Assistant."""
from __future__ import annotations
import logging
from typing import Any
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from .const import (
CONF_AGENT_NAME,
CONF_OPENCLAW_HOST,
CONF_OPENCLAW_PORT,
CONF_TIMEOUT,
DEFAULT_AGENT,
DEFAULT_HOST,
DEFAULT_PORT,
DEFAULT_TIMEOUT,
DOMAIN,
)
from .conversation import OpenClawCLIAgent
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [Platform.CONVERSATION]
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Optional(CONF_OPENCLAW_HOST, default=DEFAULT_HOST): cv.string,
vol.Optional(CONF_OPENCLAW_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_AGENT_NAME, default=DEFAULT_AGENT): cv.string,
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
}
)
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the OpenClaw Conversation component."""
hass.data.setdefault(DOMAIN, {})
if DOMAIN not in config:
return True
conf = config[DOMAIN]
# Store config
hass.data[DOMAIN] = {
"config": conf,
}
# Register the conversation agent
agent = OpenClawCLIAgent(hass, conf)
# Add to conversation agent registry
from homeassistant.components import conversation
conversation.async_set_agent(hass, DOMAIN, agent)
_LOGGER.info("OpenClaw Conversation agent registered")
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up OpenClaw Conversation from a config entry."""
hass.data.setdefault(DOMAIN, {})
# Store entry data
hass.data[DOMAIN][entry.entry_id] = entry.data
# Register the conversation agent
agent = OpenClawCLIAgent(hass, entry.data)
from homeassistant.components import conversation
conversation.async_set_agent(hass, DOMAIN, agent)
_LOGGER.info("OpenClaw Conversation agent registered from config entry")
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
# Unregister the conversation agent
from homeassistant.components import conversation
conversation.async_unset_agent(hass, DOMAIN)
hass.data[DOMAIN].pop(entry.entry_id, None)
return True