hass-core/homeassistant/components/fronius/config_flow.py
Matthias Alphart 3dac661480
Rewrite Fronius integration (#59686)
* Add unique_id and use DataUpdateCoordinator in Fronius (#57879)

* initial refactoring commit - meters

- config_flow (no strings, no tests yet)
- import yaml config
- FroniusSolarNet class for holding Fronius object , coordinators and some common data
- meter descriptions
- update coordinator
- entities (including devices)

* storage controllers

* error handling on init; inverter unique_id

* inverters

* power_flow

* fix VA, var, varh not valid for device_class power/energy

and add custom icons

* add SolarNet device for system wide values

* cleanup

* config_flow strings

* test config_flow

* use pyfronius 0.7.0

* enable strict typing

* remove TODO comments

* fix lint errors; move FroniusSensorEntity to sensor.py

* power_flow as optional coordinator

API V0 doesn't support power_flow endpoint

* show error message in logs

* prevent parallel requests to one host

* logger_info coordinator

* store FroniusSolarNet reference directly in coordinator

* cleanup coordinators when unloading entry

* round floats returned by Fronius API

* default icons for grid im/export tariffs

* small typing fix

* Update homeassistant/components/fronius/sensor.py

Co-authored-by: Brett Adams <Bre77@users.noreply.github.com>

* DC icons

* prepend names with "Fronius" and device type

to get more reasonable default entity_ids (eg. have them next to each other when alphabetically sorted)

* remove config_flow and devices

* rename _FroniusUpdateCoordinator to FroniusCoordinatorBase

and mark ABC

* move SensorEntityDescriptions to sensor.py

* Revert "move SensorEntityDescriptions to sensor.py"

This reverts commit 2e5a726eb6.

* Don't raise ConfigEntryNotReady and use regular refresh method

* move bridge initialization out of helper class

* no coverage tests

* power_flow update interval 10 seconds

* move SensorEntityDescriptions to sensor.py

without introducing a circular dependency

* deprecation warning for CONF_MONITORED_CONDITIONS

* remove extra_state_attributes form meter sensor entities

* readd diagnostic entities

* decouple default entity_id from default name

* use key instead of name for entity_id

and make deprecated config key optional

* adjust tests

* use old entity_ids

these changes are now backwards compatible

* check coverage

* simplify entity description definitions

* restore entity names of previous implementation

Co-authored-by: Brett Adams <Bre77@users.noreply.github.com>

* Add config_flow for Fronius integration (#59677)

* Cleanup Fronius config_flow and tests (#60094)

* Add devices to Fronius integration (#60104)

* New entity names for Fronius entities (#60215)

* Adaptive update interval for Fronius coordinators (#60192)

Co-authored-by: Brett Adams <Bre77@users.noreply.github.com>
2021-11-24 02:04:36 +01:00

109 lines
3.5 KiB
Python

"""Config flow for Fronius integration."""
from __future__ import annotations
import logging
from typing import Any
from pyfronius import Fronius, FroniusError
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_RESOURCE
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN, FroniusConfigEntryData
_LOGGER = logging.getLogger(__name__)
STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
}
)
async def validate_input(
hass: HomeAssistant, data: dict[str, Any]
) -> tuple[str, FroniusConfigEntryData]:
"""Validate the user input allows us to connect.
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
"""
host = data[CONF_HOST]
fronius = Fronius(async_get_clientsession(hass), host)
try:
datalogger_info: dict[str, Any]
datalogger_info = await fronius.current_logger_info()
except FroniusError as err:
_LOGGER.debug(err)
else:
logger_uid: str = datalogger_info["unique_identifier"]["value"]
return logger_uid, FroniusConfigEntryData(
host=host,
is_logger=True,
)
# Gen24 devices don't provide GetLoggerInfo
try:
inverter_info = await fronius.inverter_info()
first_inverter = next(inverter for inverter in inverter_info["inverters"])
except FroniusError as err:
_LOGGER.debug(err)
raise CannotConnect from err
except StopIteration as err:
raise CannotConnect("No supported Fronius SolarNet device found.") from err
first_inverter_uid: str = first_inverter["unique_id"]["value"]
return first_inverter_uid, FroniusConfigEntryData(
host=host,
is_logger=False,
)
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Fronius."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
if user_input is None:
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA
)
errors = {}
try:
unique_id, info = await validate_input(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(unique_id, raise_on_progress=False)
self._abort_if_unique_id_configured(
updates=dict(info), reload_on_update=False
)
title = (
f"SolarNet {'Datalogger' if info['is_logger'] else 'Inverter'}"
f" at {info['host']}"
)
return self.async_create_entry(title=title, data=info)
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
)
async def async_step_import(self, conf: dict) -> FlowResult:
"""Import a configuration from config.yaml."""
return await self.async_step_user(user_input={CONF_HOST: conf[CONF_RESOURCE]})
class CannotConnect(HomeAssistantError):
"""Error to indicate we cannot connect."""