"""Config flow for OpenClaw Conversation integration.""" from __future__ import annotations import logging from typing import Any import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_HOST, CONF_PORT from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult import homeassistant.helpers.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, ) _LOGGER = logging.getLogger(__name__) STEP_USER_DATA_SCHEMA = 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, } ) class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for OpenClaw Conversation.""" VERSION = 1 async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Handle the initial step.""" errors: dict[str, str] = {} if user_input is not None: # Validate the input try: # Test connection to OpenClaw await self._test_openclaw_connection( user_input[CONF_OPENCLAW_HOST], user_input[CONF_OPENCLAW_PORT], ) return self.async_create_entry( title="OpenClaw Conversation", data=user_input, ) except ConnectionError: errors["base"] = "cannot_connect" except Exception: _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors, ) async def _test_openclaw_connection(self, host: str, port: int) -> None: """Test if OpenClaw is reachable.""" import asyncio try: # Try to connect to OpenClaw reader, writer = await asyncio.wait_for( asyncio.open_connection(host, port), timeout=5, ) writer.close() await writer.wait_closed() except Exception as err: raise ConnectionError(f"Cannot connect to OpenClaw: {err}") @staticmethod @callback def async_get_options_flow( config_entry: config_entries.ConfigEntry, ) -> OptionsFlow: """Create the options flow.""" return OptionsFlow(config_entry) class OptionsFlow(config_entries.OptionsFlow): """Handle options flow for OpenClaw Conversation.""" def __init__(self, config_entry: config_entries.ConfigEntry) -> None: """Initialize options flow.""" self.config_entry = config_entry async def async_step_init( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Manage the options.""" errors: dict[str, str] = {} if user_input is not None: return self.async_create_entry(title="", data=user_input) options = { vol.Optional( CONF_AGENT_NAME, default=self.config_entry.options.get( CONF_AGENT_NAME, DEFAULT_AGENT ), ): cv.string, vol.Optional( CONF_TIMEOUT, default=self.config_entry.options.get( CONF_TIMEOUT, DEFAULT_TIMEOUT ), ): cv.positive_int, } return self.async_show_form( step_id="init", data_schema=vol.Schema(options), errors=errors, )