143 lines
4.0 KiB
Python
143 lines
4.0 KiB
Python
"""Config flow for XT211 HAN integration."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import logging
|
||
from typing import Any
|
||
|
||
import voluptuous as vol
|
||
|
||
from homeassistant import config_entries
|
||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_NAME
|
||
from homeassistant.data_entry_flow import FlowResult
|
||
|
||
from .const import (
|
||
DOMAIN,
|
||
DEFAULT_PORT,
|
||
DEFAULT_NAME,
|
||
CONF_PHASES,
|
||
CONF_HAS_FVE,
|
||
CONF_TARIFFS,
|
||
CONF_RELAY_COUNT,
|
||
PHASES_1,
|
||
PHASES_3,
|
||
TARIFFS_1,
|
||
TARIFFS_2,
|
||
TARIFFS_4,
|
||
RELAYS_0,
|
||
RELAYS_4,
|
||
RELAYS_6,
|
||
)
|
||
|
||
_LOGGER = logging.getLogger(__name__)
|
||
|
||
STEP_CONNECTION_SCHEMA = vol.Schema(
|
||
{
|
||
vol.Required(CONF_HOST): str,
|
||
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
|
||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): str,
|
||
}
|
||
)
|
||
|
||
STEP_METER_SCHEMA = vol.Schema(
|
||
{
|
||
vol.Required(CONF_PHASES, default=PHASES_3): vol.In(
|
||
{PHASES_1: "Jednofázový", PHASES_3: "Třífázový"}
|
||
),
|
||
vol.Required(CONF_HAS_FVE, default=False): bool,
|
||
vol.Required(CONF_TARIFFS, default=TARIFFS_2): vol.In(
|
||
{
|
||
TARIFFS_1: "Jeden tarif (pouze T1)",
|
||
TARIFFS_2: "Dva tarify (T1 + T2)",
|
||
TARIFFS_4: "Čtyři tarify (T1 – T4)",
|
||
}
|
||
),
|
||
vol.Required(CONF_RELAY_COUNT, default=RELAYS_4): vol.In(
|
||
{
|
||
RELAYS_0: "Žádné relé",
|
||
RELAYS_4: "WM-RelayBox (R1 – R4)",
|
||
RELAYS_6: "WM-RelayBox rozšířený (R1 – R6)",
|
||
}
|
||
),
|
||
}
|
||
)
|
||
|
||
|
||
async def _test_connection(host: str, port: int) -> str | None:
|
||
"""Try to open a TCP connection. Returns error string or None on success."""
|
||
try:
|
||
reader, writer = await asyncio.wait_for(
|
||
asyncio.open_connection(host, port),
|
||
timeout=5,
|
||
)
|
||
writer.close()
|
||
await writer.wait_closed()
|
||
return None
|
||
except asyncio.TimeoutError:
|
||
return "cannot_connect"
|
||
except OSError:
|
||
return "cannot_connect"
|
||
except Exception:
|
||
return "unknown"
|
||
|
||
|
||
class XT211HANConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||
"""Handle the config flow for XT211 HAN – two steps."""
|
||
|
||
VERSION = 1
|
||
|
||
def __init__(self) -> None:
|
||
self._connection_data: dict[str, Any] = {}
|
||
|
||
# ------------------------------------------------------------------
|
||
# Step 1 – connection (host / port / name)
|
||
# ------------------------------------------------------------------
|
||
|
||
async def async_step_user(
|
||
self, user_input: dict[str, Any] | None = None
|
||
) -> FlowResult:
|
||
errors: dict[str, str] = {}
|
||
|
||
if user_input is not None:
|
||
host = user_input[CONF_HOST]
|
||
port = user_input[CONF_PORT]
|
||
|
||
await self.async_set_unique_id(f"{host}:{port}")
|
||
self._abort_if_unique_id_configured()
|
||
|
||
error = await _test_connection(host, port)
|
||
if error:
|
||
errors["base"] = error
|
||
else:
|
||
self._connection_data = user_input
|
||
return await self.async_step_meter()
|
||
|
||
return self.async_show_form(
|
||
step_id="user",
|
||
data_schema=STEP_CONNECTION_SCHEMA,
|
||
errors=errors,
|
||
)
|
||
|
||
# ------------------------------------------------------------------
|
||
# Step 2 – meter configuration
|
||
# ------------------------------------------------------------------
|
||
|
||
async def async_step_meter(
|
||
self, user_input: dict[str, Any] | None = None
|
||
) -> FlowResult:
|
||
if user_input is not None:
|
||
data = {**self._connection_data, **user_input}
|
||
name = data.get(CONF_NAME, DEFAULT_NAME)
|
||
host = data[CONF_HOST]
|
||
port = data[CONF_PORT]
|
||
return self.async_create_entry(
|
||
title=f"{name} ({host}:{port})",
|
||
data=data,
|
||
)
|
||
|
||
return self.async_show_form(
|
||
step_id="meter",
|
||
data_schema=STEP_METER_SCHEMA,
|
||
)
|