Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Enigma2."""
2 
3 from typing import Any, cast
4 
5 from aiohttp.client_exceptions import ClientError
6 from openwebif.api import OpenWebIfDevice
7 from openwebif.error import InvalidAuthError
8 import voluptuous as vol
9 from yarl import URL
10 
11 from homeassistant.config_entries import (
12  SOURCE_USER,
13  ConfigEntry,
14  ConfigFlow,
15  ConfigFlowResult,
16 )
17 from homeassistant.const import (
18  CONF_HOST,
19  CONF_PASSWORD,
20  CONF_PORT,
21  CONF_SSL,
22  CONF_USERNAME,
23  CONF_VERIFY_SSL,
24 )
25 from homeassistant.core import callback
26 from homeassistant.helpers import selector
27 from homeassistant.helpers.aiohttp_client import async_create_clientsession
29  SchemaCommonFlowHandler,
30  SchemaFlowFormStep,
31  SchemaOptionsFlowHandler,
32 )
33 
34 from .const import (
35  CONF_DEEP_STANDBY,
36  CONF_SOURCE_BOUQUET,
37  CONF_USE_CHANNEL_ICON,
38  DEFAULT_PORT,
39  DEFAULT_SSL,
40  DEFAULT_VERIFY_SSL,
41  DOMAIN,
42 )
43 
44 CONFIG_SCHEMA = vol.Schema(
45  {
46  vol.Required(CONF_HOST): selector.TextSelector(),
47  vol.Required(CONF_PORT, default=DEFAULT_PORT): vol.All(
48  selector.NumberSelector(
49  selector.NumberSelectorConfig(
50  min=1, max=65535, mode=selector.NumberSelectorMode.BOX
51  )
52  ),
53  vol.Coerce(int),
54  ),
55  vol.Optional(CONF_USERNAME): selector.TextSelector(),
56  vol.Optional(CONF_PASSWORD): selector.TextSelector(
57  selector.TextSelectorConfig(type=selector.TextSelectorType.PASSWORD)
58  ),
59  vol.Required(CONF_SSL, default=DEFAULT_SSL): selector.BooleanSelector(),
60  vol.Required(
61  CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL
62  ): selector.BooleanSelector(),
63  }
64 )
65 
66 
67 async def get_options_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
68  """Get the options schema."""
69  entry = cast(SchemaOptionsFlowHandler, handler.parent_handler).config_entry
70  bouquets = [
71  b[1] for b in (await entry.runtime_data.device.get_all_bouquets())["bouquets"]
72  ]
73 
74  return vol.Schema(
75  {
76  vol.Optional(CONF_DEEP_STANDBY): selector.BooleanSelector(),
77  vol.Optional(CONF_SOURCE_BOUQUET): selector.SelectSelector(
78  selector.SelectSelectorConfig(
79  options=bouquets,
80  mode=selector.SelectSelectorMode.DROPDOWN,
81  )
82  ),
83  vol.Optional(CONF_USE_CHANNEL_ICON): selector.BooleanSelector(),
84  }
85  )
86 
87 
88 OPTIONS_FLOW = {
89  "init": SchemaFlowFormStep(get_options_schema),
90 }
91 
92 
93 class Enigma2ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
94  """Handle a config flow for Enigma2."""
95 
96  DATA_KEYS = (
97  CONF_HOST,
98  CONF_PORT,
99  CONF_USERNAME,
100  CONF_PASSWORD,
101  CONF_SSL,
102  CONF_VERIFY_SSL,
103  )
104  OPTIONS_KEYS = (CONF_DEEP_STANDBY, CONF_SOURCE_BOUQUET, CONF_USE_CHANNEL_ICON)
105 
107  self, user_input: dict[str, Any]
108  ) -> dict[str, str] | None:
109  """Validate user input."""
110 
111  errors = None
112 
113  self._async_abort_entries_match_async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]})
114 
115  base_url = URL.build(
116  scheme="http" if not user_input[CONF_SSL] else "https",
117  host=user_input[CONF_HOST],
118  port=user_input[CONF_PORT],
119  user=user_input.get(CONF_USERNAME),
120  password=user_input.get(CONF_PASSWORD),
121  )
122 
123  session = async_create_clientsession(
124  self.hass, verify_ssl=user_input[CONF_VERIFY_SSL], base_url=base_url
125  )
126 
127  try:
128  about = await OpenWebIfDevice(session).get_about()
129  except InvalidAuthError:
130  errors = {"base": "invalid_auth"}
131  except ClientError:
132  errors = {"base": "cannot_connect"}
133  except Exception: # noqa: BLE001
134  errors = {"base": "unknown"}
135  else:
136  await self.async_set_unique_idasync_set_unique_id(about["info"]["ifaces"][0]["mac"])
137  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
138 
139  return errors
140 
141  async def async_step_user(
142  self, user_input: dict[str, Any] | None = None
143  ) -> ConfigFlowResult:
144  """Handle the user step."""
145  if user_input is None:
146  return self.async_show_formasync_show_formasync_show_form(step_id=SOURCE_USER, data_schema=CONFIG_SCHEMA)
147 
148  if errors := await self.validate_user_inputvalidate_user_input(user_input):
149  return self.async_show_formasync_show_formasync_show_form(
150  step_id=SOURCE_USER, data_schema=CONFIG_SCHEMA, errors=errors
151  )
152  return self.async_create_entryasync_create_entryasync_create_entry(data=user_input, title=user_input[CONF_HOST])
153 
154  @staticmethod
155  @callback
156  def async_get_options_flow(config_entry: ConfigEntry) -> SchemaOptionsFlowHandler:
157  """Get the options flow for this handler."""
158  return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
dict[str, str]|None validate_user_input(self, dict[str, Any] user_input)
Definition: config_flow.py:108
SchemaOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
Definition: config_flow.py:156
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:143
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry|None async_set_unique_id(self, str|None unique_id=None, *bool raise_on_progress=True)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
None _async_abort_entries_match(self, dict[str, Any]|None match_dict=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
vol.Schema get_options_schema(SchemaCommonFlowHandler handler)
Definition: config_flow.py:67
aiohttp.ClientSession async_create_clientsession()
Definition: coordinator.py:51