Hello together,
i am currently writing my first integration. Already was able to enable users to manually configure the integration during setup in the GUI. This is working as expected. The configuration parameter will be set and used.
In a next step i plan to make just one specific parameter configureable after setup. I go over the docs and found ConfigFlowHandler is the way to go. I used the code as documented
Unfortunately it is not working.
I plan to make the scan_interval parameter configurable. Below you can find the relevant class in ConfigFlow.py
What currently happens:
- I can click on configure and actually see the option to reconfigure the scan_interval.
- The actual change of this value does not get saved. If i reopen the configure menu the old value will appear again
I am confused… checked different other projects but i stuck. Do you maybe have an idea whats the issue?
class OptionsFlowHandler(config_entries.OptionsFlow):
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."""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)
return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Required(
"scan_interval",
default=self.config_entry.data.get("scan_interval"),
): int
}
),
)
This is the complete ConfigFlow.py
"""Config flow for VARTA Storage integration."""
from __future__ import annotations
from typing import Any
from vartastorage import vartastorage
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SCAN_INTERVAL
from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_validation as cv
from homeassistant.exceptions import HomeAssistantError
from .const import DOMAIN, LOGGER, DEFAULT_SCAN_INTERVAL
STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=502): int,
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): int,
}
)
class VartaHub:
"""Provide methods for GUI configuration."""
def __init__(self, host: str, port: int, scan_interval: cv.time_period) -> None:
"""Initialize."""
self.host = host
self.port = port
self.serial = ""
self.scan_interval = scan_interval
def test_connection(self) -> bool:
"""Tests a connection to the VartaStorage device."""
varta = vartastorage.VartaStorage(self.host, self.port)
try:
varta.get_serial()
self.serial = varta.serial
return bool(varta.client.connect())
except ValueError:
return False
async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]:
"""Validate the user input allows us to connect.
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
"""
hub = VartaHub(data["host"], data["port"], data["scan_interval"])
# Used PyPI package is not built with async, passing to the sync executor.
if not await hass.async_add_executor_job(hub.test_connection):
raise CannotConnect
# Return info stored in the config entry.
return {
"title": f"{data['host']} (S/N: {hub.serial} )",
"serial": hub.serial,
"scan_interval": hub.scan_interval,
}
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for VARTA Storage."""
@staticmethod
@callback
def async_get_options_flow(
config_entry: config_entries.ConfigEntry,
) -> config_entries.OptionsFlow:
"""Create the options flow."""
return OptionsFlowHandler(config_entry)
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:
info = await validate_input(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except Exception: # pylint: disable=broad-except
LOGGER.warning("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(info["serial"])
self._abort_if_unique_id_configured()
return self.async_create_entry(title=info["title"], data=user_input)
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
)
class CannotConnect(HomeAssistantError):
"""Error to indicate we cannot connect."""
class OptionsFlowHandler(config_entries.OptionsFlow):
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."""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)
return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Required(
"scan_interval",
default=self.config_entry.data.get("scan_interval"),
): int
}
),
)