| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- """Config flow for Integration 101 Template integration."""
- from __future__ import annotations
- import logging
- from typing import Any
- import voluptuous as vol
- from homeassistant.config_entries import (
- ConfigEntry,
- ConfigFlow,
- ConfigFlowResult,
- OptionsFlow,
- )
- from homeassistant.const import (
- CONF_HOST,
- CONF_PASSWORD,
- CONF_SCAN_INTERVAL,
- CONF_USERNAME,
- )
- from homeassistant.core import HomeAssistant, callback
- from homeassistant.exceptions import HomeAssistantError
- from homeassistant.helpers.aiohttp_client import async_get_clientsession
- from .api import (RouterAPI,
- RouterAPIAuthError,
- RouterAPIConnectionError)
- from .const import (DEFAULT_SCAN_INTERVAL,
- DOMAIN,
- MIN_SCAN_INTERVAL,
- DEFAULT_IP,
- DEFAULT_USER)
- _LOGGER = logging.getLogger(__name__)
- # TODO adjust the data schema to the data that you need
- STEP_USER_DATA_SCHEMA = vol.Schema(
- {
- vol.Required(CONF_HOST, description={"suggested_value": DEFAULT_IP}): str,
- vol.Required(CONF_USERNAME, description={"suggested_value": DEFAULT_USER}): str,
- vol.Required(CONF_PASSWORD): str,
- }
- )
- 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.
- """
- # TODO validate the data can be used to set up a connection.
- # If your PyPI package is not built with async, pass your methods
- # to the executor:
- # await hass.async_add_executor_job(
- # your_validate_func, data[CONF_USERNAME], data[CONF_PASSWORD]
- # )
- session = async_get_clientsession(
- hass=hass,
- verify_ssl=False
- )
- api = RouterAPI(host=data[CONF_HOST],
- user=data[CONF_USERNAME],
- pwd=data[CONF_PASSWORD],
- session=session)
- try:
- await api.async_login()
- except RouterAPIAuthError as err:
- raise InvalidAuth from err
- except RouterAPIConnectionError as err:
- raise CannotConnect from err
-
- return {"title": f"Odido Klik & Klaar router - {data[CONF_HOST]}"}
- class RouterConfigFlow(ConfigFlow, domain=DOMAIN):
- """Handle a config flow for Example Integration."""
- VERSION = 1
- _input_data: dict[str, Any]
- @staticmethod
- @callback
- def async_get_options_flow(config_entry):
- """Get the options flow for this handler."""
- # Remove this method and the ExampleOptionsFlowHandler class
- # if you do not want any options for your integration.
- return RouterOptionsFlowHandler(config_entry)
- async def async_step_user(
- self, user_input: dict[str, Any] | None = None
- ) -> ConfigFlowResult:
- """Handle the initial step."""
- # Called when you initiate adding an integration via the UI
- errors: dict[str, str] = {}
- if user_input is not None:
- # The form has been filled in and submitted, so process the data provided.
- try:
- # Validate that the setup data is valid and if not handle errors.
- # The errors["base"] values match the values in your strings.json and translation files.
- info = await validate_input(self.hass, user_input)
- except CannotConnect:
- errors["base"] = "cannot_connect"
- except InvalidAuth:
- errors["base"] = "invalid_auth"
- except Exception as e: # pylint: disable=broad-except
- _LOGGER.exception(f"Unexpected exception: {e}")
- errors["base"] = "unknown"
- #errors[CONF_PASSWORD] = str(e)
- if "base" not in errors:
- # Validation was successful, so create a unique id for this instance of your integration
- # and create the config entry.
- await self.async_set_unique_id(info.get("title"))
- self._abort_if_unique_id_configured()
- return self.async_create_entry(title=info["title"], data=user_input)
- # Show initial form.
- return self.async_show_form(
- step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
- )
- async def async_step_reconfigure(
- self, user_input: dict[str, Any] | None = None
- ) -> ConfigFlowResult:
- """Add reconfigure step to allow to reconfigure a config entry."""
- # This methid displays a reconfigure option in the integration and is
- # different to options.
- # It can be used to reconfigure any of the data submitted when first installed.
- # This is optional and can be removed if you do not want to allow reconfiguration.
- errors: dict[str, str] = {}
- config_entry = self.hass.config_entries.async_get_entry(
- self.context["entry_id"]
- )
- if user_input is not None:
- try:
- user_input[CONF_HOST] = config_entry.data[CONF_HOST]
- await validate_input(self.hass, user_input)
- except CannotConnect:
- errors["base"] = "cannot_connect"
- except InvalidAuth:
- errors["base"] = "invalid_auth"
- except Exception: # pylint: disable=broad-except
- _LOGGER.exception("Unexpected exception")
- errors["base"] = "unknown"
- else:
- return self.async_update_reload_and_abort(
- config_entry,
- unique_id=config_entry.unique_id,
- data={**config_entry.data, **user_input},
- reason="reconfigure_successful",
- )
- return self.async_show_form(
- step_id="reconfigure",
- data_schema=vol.Schema(
- {
- vol.Required(
- CONF_USERNAME, default=config_entry.data[CONF_USERNAME]
- ): str,
- vol.Required(CONF_PASSWORD): str,
- }
- ),
- errors=errors,
- )
- class RouterOptionsFlowHandler(OptionsFlow):
- """Handles the options flow."""
- def __init__(self, config_entry: ConfigEntry) -> None:
- """Initialize options flow."""
- self.config_entry = config_entry
- self.options = dict(config_entry.options)
- async def async_step_init(self, user_input=None):
- """Handle options flow."""
- if user_input is not None:
- options = self.config_entry.options | user_input
- return self.async_create_entry(title="", data=options)
- # It is recommended to prepopulate options fields with default values if available.
- # These will be the same default values you use on your coordinator for setting variable values
- # if the option has not been set.
- data_schema = vol.Schema(
- {
- vol.Required(
- CONF_SCAN_INTERVAL,
- default=self.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL),
- ): (vol.All(vol.Coerce(int), vol.Clamp(min=MIN_SCAN_INTERVAL))),
- }
- )
- return self.async_show_form(step_id="init", data_schema=data_schema)
- class CannotConnect(HomeAssistantError):
- """Error to indicate we cannot connect."""
- class InvalidAuth(HomeAssistantError):
- """Error to indicate there is invalid auth."""
|