mirror of
https://github.com/home-assistant/core.git
synced 2026-09-05 21:12:24 +01:00
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
147 lines
5.1 KiB
Python
147 lines
5.1 KiB
Python
"""Config flow for solax integration."""
|
|
|
|
import asyncio
|
|
import logging
|
|
from typing import Any, override
|
|
|
|
from solax import RealTimeAPI, discover
|
|
from solax.discovery import DiscoveryError
|
|
from solax.inverter import Inverter, InverterError
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
|
from homeassistant.const import CONF_IP_ADDRESS, CONF_MODEL, CONF_PASSWORD, CONF_PORT
|
|
from homeassistant.helpers import config_validation as cv, selector
|
|
|
|
from .const import DOMAIN, model_name_for_inverter
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
DEFAULT_PORT = 80
|
|
DEFAULT_PASSWORD = ""
|
|
|
|
STEP_USER_DATA_SCHEMA = vol.Schema(
|
|
{
|
|
vol.Required(CONF_IP_ADDRESS): cv.string,
|
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
|
vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string,
|
|
}
|
|
)
|
|
|
|
|
|
class SolaxConfigFlow(ConfigFlow, domain=DOMAIN):
|
|
"""Handle a config flow for Solax.
|
|
|
|
Two step flow:
|
|
1. Get connection data and do a discovery
|
|
2. If multiple inverters are returned from step 1, then show them to the user to choose one. If one is returned, skip this step.
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
"""Initialize the flow."""
|
|
super().__init__()
|
|
self._connection_data: dict[str, Any] = {}
|
|
self._potential_types: dict[str, Inverter] = {}
|
|
|
|
def _select_model_schema(self) -> vol.Schema:
|
|
"""Return the schema listing only the discovered inverters."""
|
|
return vol.Schema(
|
|
{
|
|
vol.Required(CONF_MODEL): selector.SelectSelector(
|
|
selector.SelectSelectorConfig(
|
|
options=sorted(self._potential_types),
|
|
mode=selector.SelectSelectorMode.DROPDOWN,
|
|
)
|
|
)
|
|
}
|
|
)
|
|
|
|
async def _async_finalize(
|
|
self, model: str, inverter: Inverter, *, step_id: str, data_schema: vol.Schema
|
|
) -> ConfigFlowResult:
|
|
"""Fetch the serial number and create the entry, or redisplay on error."""
|
|
errors: dict[str, str] = {}
|
|
try:
|
|
response = await RealTimeAPI(inverter).get_data()
|
|
except ConnectionError, DiscoveryError:
|
|
errors["base"] = "cannot_connect"
|
|
except InverterError as err:
|
|
_LOGGER.debug("Inverter communication error: %s", err)
|
|
errors["base"] = "cannot_connect"
|
|
except Exception:
|
|
_LOGGER.exception("Unexpected exception")
|
|
errors["base"] = "unknown"
|
|
else:
|
|
await self.async_set_unique_id(response.serial_number)
|
|
self._abort_if_unique_id_configured()
|
|
return self.async_create_entry(
|
|
title=response.serial_number,
|
|
data={**self._connection_data, CONF_MODEL: model},
|
|
)
|
|
|
|
return self.async_show_form(
|
|
step_id=step_id, data_schema=data_schema, errors=errors
|
|
)
|
|
|
|
@override
|
|
async def async_step_user(
|
|
self, user_input: dict[str, Any] | None = None
|
|
) -> ConfigFlowResult:
|
|
"""Shows the connection form, and do the discovery.
|
|
|
|
If discovery resulted in multiple inverters, show the select_model form,
|
|
If only one skip and finalize.
|
|
"""
|
|
if user_input is None:
|
|
return self.async_show_form(
|
|
step_id="user", data_schema=STEP_USER_DATA_SCHEMA
|
|
)
|
|
|
|
errors: dict[str, str] = {}
|
|
try:
|
|
potentials = await discover(
|
|
user_input[CONF_IP_ADDRESS],
|
|
user_input[CONF_PORT],
|
|
user_input[CONF_PASSWORD],
|
|
return_when=asyncio.ALL_COMPLETED,
|
|
)
|
|
except ConnectionError, DiscoveryError:
|
|
errors["base"] = "cannot_connect"
|
|
except Exception:
|
|
_LOGGER.exception("Unexpected exception")
|
|
errors["base"] = "unknown"
|
|
else:
|
|
self._potential_types = {
|
|
model_name_for_inverter(inverter): inverter for inverter in potentials
|
|
}
|
|
self._connection_data = user_input
|
|
|
|
if len(self._potential_types) > 1:
|
|
return await self.async_step_select_model()
|
|
|
|
model, inverter = next(iter(self._potential_types.items()))
|
|
return await self._async_finalize(
|
|
model, inverter, step_id="user", data_schema=STEP_USER_DATA_SCHEMA
|
|
)
|
|
|
|
return self.async_show_form(
|
|
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
|
)
|
|
|
|
async def async_step_select_model(
|
|
self, user_input: dict[str, Any] | None = None
|
|
) -> ConfigFlowResult:
|
|
"""Handle model selection when multiple inverters matched."""
|
|
if user_input is not None:
|
|
model = user_input[CONF_MODEL]
|
|
return await self._async_finalize(
|
|
model,
|
|
self._potential_types[model],
|
|
step_id="select_model",
|
|
data_schema=self._select_model_schema(),
|
|
)
|
|
|
|
return self.async_show_form(
|
|
step_id="select_model", data_schema=self._select_model_schema()
|
|
)
|