Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Lutron Homeworks Series 4 and 8 config flow."""
2 
3 from __future__ import annotations
4 
5 from functools import partial
6 import logging
7 from typing import Any
8 
9 from pyhomeworks import exceptions as hw_exceptions
10 from pyhomeworks.pyhomeworks import Homeworks
11 import voluptuous as vol
12 
13 from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
14 from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
15 from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
16 from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult
17 from homeassistant.const import (
18  CONF_HOST,
19  CONF_NAME,
20  CONF_PASSWORD,
21  CONF_PORT,
22  CONF_USERNAME,
23 )
24 from homeassistant.core import async_get_hass, callback
25 from homeassistant.data_entry_flow import AbortFlow
26 from homeassistant.helpers import (
27  config_validation as cv,
28  entity_registry as er,
29  selector,
30 )
32  SchemaCommonFlowHandler,
33  SchemaFlowError,
34  SchemaFlowFormStep,
35  SchemaFlowMenuStep,
36  SchemaOptionsFlowHandler,
37 )
38 from homeassistant.helpers.selector import TextSelector
39 from homeassistant.helpers.typing import VolDictType
40 from homeassistant.util import slugify
41 
42 from .const import (
43  CONF_ADDR,
44  CONF_BUTTONS,
45  CONF_CONTROLLER_ID,
46  CONF_DIMMERS,
47  CONF_INDEX,
48  CONF_KEYPADS,
49  CONF_LED,
50  CONF_NUMBER,
51  CONF_RATE,
52  CONF_RELEASE_DELAY,
53  DEFAULT_BUTTON_NAME,
54  DEFAULT_KEYPAD_NAME,
55  DEFAULT_LIGHT_NAME,
56  DOMAIN,
57 )
58 from .util import calculate_unique_id
59 
60 _LOGGER = logging.getLogger(__name__)
61 
62 DEFAULT_FADE_RATE = 1.0
63 
64 CONTROLLER_EDIT = {
65  vol.Required(CONF_HOST): selector.TextSelector(),
66  vol.Required(CONF_PORT): selector.NumberSelector(
67  selector.NumberSelectorConfig(
68  min=1,
69  max=65535,
70  mode=selector.NumberSelectorMode.BOX,
71  )
72  ),
73  vol.Optional(CONF_USERNAME): selector.TextSelector(),
74  vol.Optional(CONF_PASSWORD): selector.TextSelector(
75  selector.TextSelectorConfig(type=selector.TextSelectorType.PASSWORD)
76  ),
77 }
78 
79 LIGHT_EDIT: VolDictType = {
80  vol.Optional(CONF_RATE, default=DEFAULT_FADE_RATE): selector.NumberSelector(
81  selector.NumberSelectorConfig(
82  min=0,
83  max=20,
84  mode=selector.NumberSelectorMode.SLIDER,
85  step=0.1,
86  )
87  ),
88 }
89 
90 BUTTON_EDIT: VolDictType = {
91  vol.Optional(CONF_LED, default=False): selector.BooleanSelector(),
92  vol.Optional(CONF_RELEASE_DELAY, default=0): selector.NumberSelector(
93  selector.NumberSelectorConfig(
94  min=0,
95  max=5,
96  step=0.01,
97  mode=selector.NumberSelectorMode.BOX,
98  unit_of_measurement="s",
99  ),
100  ),
101 }
102 
103 
104 validate_addr = cv.matches_regex(r"\[(?:\d\d:){2,4}\d\d\]")
105 
106 
107 def _validate_credentials(user_input: dict[str, Any]) -> None:
108  """Validate credentials."""
109  if CONF_PASSWORD in user_input and CONF_USERNAME not in user_input:
110  raise SchemaFlowError("need_username_with_password")
111 
112 
114  handler: ConfigFlow | SchemaOptionsFlowHandler, user_input: dict[str, Any]
115 ) -> dict[str, Any]:
116  """Validate controller setup."""
117  _validate_credentials(user_input)
118  user_input[CONF_CONTROLLER_ID] = slugify(user_input[CONF_NAME])
119  user_input[CONF_PORT] = int(user_input[CONF_PORT])
120  try:
121  handler._async_abort_entries_match( # noqa: SLF001
122  {CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]}
123  )
124  except AbortFlow as err:
125  raise SchemaFlowError("duplicated_host_port") from err
126 
127  try:
128  handler._async_abort_entries_match( # noqa: SLF001
129  {CONF_CONTROLLER_ID: user_input[CONF_CONTROLLER_ID]}
130  )
131  except AbortFlow as err:
132  raise SchemaFlowError("duplicated_controller_id") from err
133 
134  await _try_connection(user_input)
135 
136  return user_input
137 
138 
139 async def _try_connection(user_input: dict[str, Any]) -> None:
140  """Try connecting to the controller."""
141 
142  def _try_connect(host: str, port: int) -> None:
143  """Try connecting to the controller.
144 
145  Raises ConnectionError if the connection fails.
146  """
147  _LOGGER.debug(
148  "Trying to connect to %s:%s", user_input[CONF_HOST], user_input[CONF_PORT]
149  )
150  controller = Homeworks(
151  host,
152  port,
153  lambda msg_types, values: None,
154  user_input.get(CONF_USERNAME),
155  user_input.get(CONF_PASSWORD),
156  )
157  controller.connect()
158  controller.close()
159 
160  hass = async_get_hass()
161  try:
162  await hass.async_add_executor_job(
163  _try_connect, user_input[CONF_HOST], user_input[CONF_PORT]
164  )
165  except hw_exceptions.HomeworksConnectionFailed as err:
166  _LOGGER.debug("Caught HomeworksConnectionFailed")
167  raise SchemaFlowError("connection_error") from err
168  except hw_exceptions.HomeworksInvalidCredentialsProvided as err:
169  _LOGGER.debug("Caught HomeworksInvalidCredentialsProvided")
170  raise SchemaFlowError("invalid_credentials") from err
171  except hw_exceptions.HomeworksNoCredentialsProvided as err:
172  _LOGGER.debug("Caught HomeworksNoCredentialsProvided")
173  raise SchemaFlowError("credentials_needed") from err
174  except Exception as err:
175  _LOGGER.exception("Caught unexpected exception %s")
176  raise SchemaFlowError("unknown_error") from err
177 
178 
179 def _validate_address(handler: SchemaCommonFlowHandler, addr: str) -> None:
180  """Validate address."""
181  try:
182  validate_addr(addr)
183  except vol.Invalid as err:
184  raise SchemaFlowError("invalid_addr") from err
185 
186  for _key in (CONF_DIMMERS, CONF_KEYPADS):
187  items: list[dict[str, Any]] = handler.options[_key]
188 
189  for item in items:
190  if item[CONF_ADDR] == addr:
191  raise SchemaFlowError("duplicated_addr")
192 
193 
194 def _validate_button_number(handler: SchemaCommonFlowHandler, number: int) -> None:
195  """Validate button number."""
196  keypad = handler.flow_state["_idx"]
197  buttons: list[dict[str, Any]] = handler.options[CONF_KEYPADS][keypad][CONF_BUTTONS]
198 
199  for button in buttons:
200  if button[CONF_NUMBER] == number:
201  raise SchemaFlowError("duplicated_number")
202 
203 
205  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
206 ) -> dict[str, Any]:
207  """Validate button input."""
208  user_input[CONF_NUMBER] = int(user_input[CONF_NUMBER])
209  _validate_button_number(handler, user_input[CONF_NUMBER])
210 
211  # Standard behavior is to merge the result with the options.
212  # In this case, we want to add a sub-item so we update the options directly.
213  keypad = handler.flow_state["_idx"]
214  buttons: list[dict[str, Any]] = handler.options[CONF_KEYPADS][keypad][CONF_BUTTONS]
215  buttons.append(user_input)
216  return {}
217 
218 
220  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
221 ) -> dict[str, Any]:
222  """Validate keypad or light input."""
223  _validate_address(handler, user_input[CONF_ADDR])
224 
225  # Standard behavior is to merge the result with the options.
226  # In this case, we want to add a sub-item so we update the options directly.
227  items = handler.options[CONF_KEYPADS]
228  items.append(user_input | {CONF_BUTTONS: []})
229  return {}
230 
231 
233  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
234 ) -> dict[str, Any]:
235  """Validate light input."""
236  _validate_address(handler, user_input[CONF_ADDR])
237 
238  # Standard behavior is to merge the result with the options.
239  # In this case, we want to add a sub-item so we update the options directly.
240  items = handler.options[CONF_DIMMERS]
241  items.append(user_input)
242  return {}
243 
244 
245 async def get_select_button_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
246  """Return schema for selecting a button."""
247  keypad = handler.flow_state["_idx"]
248  buttons: list[dict[str, Any]] = handler.options[CONF_KEYPADS][keypad][CONF_BUTTONS]
249 
250  return vol.Schema(
251  {
252  vol.Required(CONF_INDEX): vol.In(
253  {
254  str(index): f"{config[CONF_NAME]} ({config[CONF_NUMBER]})"
255  for index, config in enumerate(buttons)
256  },
257  )
258  }
259  )
260 
261 
262 async def get_select_keypad_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
263  """Return schema for selecting a keypad."""
264  return vol.Schema(
265  {
266  vol.Required(CONF_INDEX): vol.In(
267  {
268  str(index): f"{config[CONF_NAME]} ({config[CONF_ADDR]})"
269  for index, config in enumerate(handler.options[CONF_KEYPADS])
270  },
271  )
272  }
273  )
274 
275 
276 async def get_select_light_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
277  """Return schema for selecting a light."""
278  return vol.Schema(
279  {
280  vol.Required(CONF_INDEX): vol.In(
281  {
282  str(index): f"{config[CONF_NAME]} ({config[CONF_ADDR]})"
283  for index, config in enumerate(handler.options[CONF_DIMMERS])
284  },
285  )
286  }
287  )
288 
289 
291  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
292 ) -> dict[str, Any]:
293  """Store button index in flow state."""
294  handler.flow_state["_button_idx"] = int(user_input[CONF_INDEX])
295  return {}
296 
297 
299  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
300 ) -> dict[str, Any]:
301  """Store keypad or light index in flow state."""
302  handler.flow_state["_idx"] = int(user_input[CONF_INDEX])
303  return {}
304 
305 
307  handler: SchemaCommonFlowHandler,
308 ) -> dict[str, Any]:
309  """Return suggested values for button editing."""
310  keypad_idx: int = handler.flow_state["_idx"]
311  button_idx: int = handler.flow_state["_button_idx"]
312  return dict(handler.options[CONF_KEYPADS][keypad_idx][CONF_BUTTONS][button_idx])
313 
314 
316  handler: SchemaCommonFlowHandler,
317 ) -> dict[str, Any]:
318  """Return suggested values for light editing."""
319  idx: int = handler.flow_state["_idx"]
320  return dict(handler.options[CONF_DIMMERS][idx])
321 
322 
324  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
325 ) -> dict[str, Any]:
326  """Update edited keypad or light."""
327  # Standard behavior is to merge the result with the options.
328  # In this case, we want to add a sub-item so we update the options directly.
329  keypad_idx: int = handler.flow_state["_idx"]
330  button_idx: int = handler.flow_state["_button_idx"]
331  buttons: list[dict] = handler.options[CONF_KEYPADS][keypad_idx][CONF_BUTTONS]
332  buttons[button_idx].update(user_input)
333  return {}
334 
335 
337  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
338 ) -> dict[str, Any]:
339  """Update edited keypad or light."""
340  # Standard behavior is to merge the result with the options.
341  # In this case, we want to add a sub-item so we update the options directly.
342  idx: int = handler.flow_state["_idx"]
343  handler.options[CONF_DIMMERS][idx].update(user_input)
344  return {}
345 
346 
347 async def get_remove_button_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
348  """Return schema for button removal."""
349  keypad_idx: int = handler.flow_state["_idx"]
350  buttons: list[dict] = handler.options[CONF_KEYPADS][keypad_idx][CONF_BUTTONS]
351  return vol.Schema(
352  {
353  vol.Required(CONF_INDEX): cv.multi_select(
354  {
355  str(index): f"{config[CONF_NAME]} ({config[CONF_NUMBER]})"
356  for index, config in enumerate(buttons)
357  },
358  )
359  }
360  )
361 
362 
364  handler: SchemaCommonFlowHandler, *, key: str
365 ) -> vol.Schema:
366  """Return schema for keypad or light removal."""
367  return vol.Schema(
368  {
369  vol.Required(CONF_INDEX): cv.multi_select(
370  {
371  str(index): f"{config[CONF_NAME]} ({config[CONF_ADDR]})"
372  for index, config in enumerate(handler.options[key])
373  },
374  )
375  }
376  )
377 
378 
380  handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
381 ) -> dict[str, Any]:
382  """Validate remove keypad or light."""
383  removed_indexes: set[str] = set(user_input[CONF_INDEX])
384 
385  # Standard behavior is to merge the result with the options.
386  # In this case, we want to remove sub-items so we update the options directly.
387  entity_registry = er.async_get(handler.parent_handler.hass)
388  keypad_idx: int = handler.flow_state["_idx"]
389  keypad: dict = handler.options[CONF_KEYPADS][keypad_idx]
390  items: list[dict[str, Any]] = []
391  item: dict[str, Any]
392  for index, item in enumerate(keypad[CONF_BUTTONS]):
393  if str(index) not in removed_indexes:
394  items.append(item)
395  button_number = keypad[CONF_BUTTONS][index][CONF_NUMBER]
396  for domain in (BINARY_SENSOR_DOMAIN, BUTTON_DOMAIN):
397  if entity_id := entity_registry.async_get_entity_id(
398  domain,
399  DOMAIN,
401  handler.options[CONF_CONTROLLER_ID],
402  keypad[CONF_ADDR],
403  button_number,
404  ),
405  ):
406  entity_registry.async_remove(entity_id)
407  keypad[CONF_BUTTONS] = items
408  return {}
409 
410 
412  handler: SchemaCommonFlowHandler, user_input: dict[str, Any], *, key: str
413 ) -> dict[str, Any]:
414  """Validate remove keypad or light."""
415  removed_indexes: set[str] = set(user_input[CONF_INDEX])
416 
417  # Standard behavior is to merge the result with the options.
418  # In this case, we want to remove sub-items so we update the options directly.
419  entity_registry = er.async_get(handler.parent_handler.hass)
420  items: list[dict[str, Any]] = []
421  item: dict[str, Any]
422  for index, item in enumerate(handler.options[key]):
423  if str(index) not in removed_indexes:
424  items.append(item)
425  elif key != CONF_DIMMERS:
426  continue
427  if entity_id := entity_registry.async_get_entity_id(
428  LIGHT_DOMAIN,
429  DOMAIN,
431  handler.options[CONF_CONTROLLER_ID], item[CONF_ADDR], 0
432  ),
433  ):
434  entity_registry.async_remove(entity_id)
435  handler.options[key] = items
436  return {}
437 
438 
439 DATA_SCHEMA_ADD_CONTROLLER = vol.Schema(
440  {
441  vol.Required(
442  CONF_NAME, description={"suggested_value": "Lutron Homeworks"}
443  ): selector.TextSelector(),
444  **CONTROLLER_EDIT,
445  }
446 )
447 DATA_SCHEMA_EDIT_CONTROLLER = vol.Schema(CONTROLLER_EDIT)
448 DATA_SCHEMA_ADD_LIGHT = vol.Schema(
449  {
450  vol.Optional(CONF_NAME, default=DEFAULT_LIGHT_NAME): TextSelector(),
451  vol.Required(CONF_ADDR): TextSelector(),
452  **LIGHT_EDIT,
453  }
454 )
455 DATA_SCHEMA_ADD_KEYPAD = vol.Schema(
456  {
457  vol.Optional(CONF_NAME, default=DEFAULT_KEYPAD_NAME): TextSelector(),
458  vol.Required(CONF_ADDR): TextSelector(),
459  }
460 )
461 DATA_SCHEMA_ADD_BUTTON = vol.Schema(
462  {
463  vol.Optional(CONF_NAME, default=DEFAULT_BUTTON_NAME): TextSelector(),
464  vol.Required(CONF_NUMBER): selector.NumberSelector(
465  selector.NumberSelectorConfig(
466  min=1,
467  max=24,
468  step=1,
469  mode=selector.NumberSelectorMode.BOX,
470  ),
471  ),
472  **BUTTON_EDIT,
473  }
474 )
475 DATA_SCHEMA_EDIT_BUTTON = vol.Schema(BUTTON_EDIT)
476 DATA_SCHEMA_EDIT_LIGHT = vol.Schema(LIGHT_EDIT)
477 
478 OPTIONS_FLOW = {
479  "init": SchemaFlowMenuStep(
480  [
481  "add_keypad",
482  "select_edit_keypad",
483  "remove_keypad",
484  "add_light",
485  "select_edit_light",
486  "remove_light",
487  ]
488  ),
489  "add_keypad": SchemaFlowFormStep(
490  DATA_SCHEMA_ADD_KEYPAD,
491  suggested_values=None,
492  validate_user_input=validate_add_keypad,
493  ),
494  "select_edit_keypad": SchemaFlowFormStep(
495  get_select_keypad_schema,
496  suggested_values=None,
497  validate_user_input=validate_select_keypad_light,
498  next_step="edit_keypad",
499  ),
500  "edit_keypad": SchemaFlowMenuStep(
501  [
502  "add_button",
503  "select_edit_button",
504  "remove_button",
505  ]
506  ),
507  "add_button": SchemaFlowFormStep(
508  DATA_SCHEMA_ADD_BUTTON,
509  suggested_values=None,
510  validate_user_input=validate_add_button,
511  ),
512  "select_edit_button": SchemaFlowFormStep(
513  get_select_button_schema,
514  suggested_values=None,
515  validate_user_input=validate_select_button,
516  next_step="edit_button",
517  ),
518  "edit_button": SchemaFlowFormStep(
519  DATA_SCHEMA_EDIT_BUTTON,
520  suggested_values=get_edit_button_suggested_values,
521  validate_user_input=validate_button_edit,
522  ),
523  "remove_button": SchemaFlowFormStep(
524  get_remove_button_schema,
525  suggested_values=None,
526  validate_user_input=validate_remove_button,
527  ),
528  "remove_keypad": SchemaFlowFormStep(
529  partial(get_remove_keypad_light_schema, key=CONF_KEYPADS),
530  suggested_values=None,
531  validate_user_input=partial(validate_remove_keypad_light, key=CONF_KEYPADS),
532  ),
533  "add_light": SchemaFlowFormStep(
534  DATA_SCHEMA_ADD_LIGHT,
535  suggested_values=None,
536  validate_user_input=validate_add_light,
537  ),
538  "select_edit_light": SchemaFlowFormStep(
539  get_select_light_schema,
540  suggested_values=None,
541  validate_user_input=validate_select_keypad_light,
542  next_step="edit_light",
543  ),
544  "edit_light": SchemaFlowFormStep(
545  DATA_SCHEMA_EDIT_LIGHT,
546  suggested_values=get_edit_light_suggested_values,
547  validate_user_input=validate_light_edit,
548  ),
549  "remove_light": SchemaFlowFormStep(
550  partial(get_remove_keypad_light_schema, key=CONF_DIMMERS),
551  suggested_values=None,
552  validate_user_input=partial(validate_remove_keypad_light, key=CONF_DIMMERS),
553  ),
554 }
555 
556 
558  """Config flow for Lutron Homeworks."""
559 
561  self, user_input: dict[str, Any], reconfigure_entry: ConfigEntry
562  ) -> dict[str, Any]:
563  """Validate controller setup."""
564  _validate_credentials(user_input)
565  user_input[CONF_PORT] = int(user_input[CONF_PORT])
566 
567  if any(
568  entry.entry_id != reconfigure_entry.entry_id
569  and user_input[CONF_HOST] == entry.options[CONF_HOST]
570  and user_input[CONF_PORT] == entry.options[CONF_PORT]
571  for entry in self._async_current_entries_async_current_entries()
572  ):
573  raise SchemaFlowError("duplicated_host_port")
574 
575  await _try_connection(user_input)
576  return user_input
577 
578  async def async_step_reconfigure(
579  self, user_input: dict[str, Any] | None = None
580  ) -> ConfigFlowResult:
581  """Handle a reconfigure flow."""
582  errors = {}
583  reconfigure_entry = self._get_reconfigure_entry_get_reconfigure_entry()
584  suggested_values = {
585  CONF_HOST: reconfigure_entry.options[CONF_HOST],
586  CONF_PORT: reconfigure_entry.options[CONF_PORT],
587  CONF_USERNAME: reconfigure_entry.data.get(CONF_USERNAME),
588  CONF_PASSWORD: reconfigure_entry.data.get(CONF_PASSWORD),
589  }
590 
591  if user_input:
592  suggested_values = {
593  CONF_HOST: user_input[CONF_HOST],
594  CONF_PORT: user_input[CONF_PORT],
595  CONF_USERNAME: user_input.get(CONF_USERNAME),
596  CONF_PASSWORD: user_input.get(CONF_PASSWORD),
597  }
598  try:
599  await self._validate_edit_controller_validate_edit_controller(user_input, reconfigure_entry)
600  except SchemaFlowError as err:
601  errors["base"] = str(err)
602  else:
603  password = user_input.pop(CONF_PASSWORD, None)
604  username = user_input.pop(CONF_USERNAME, None)
605  new_data = reconfigure_entry.data | {
606  CONF_PASSWORD: password,
607  CONF_USERNAME: username,
608  }
609  new_options = reconfigure_entry.options | {
610  CONF_HOST: user_input[CONF_HOST],
611  CONF_PORT: user_input[CONF_PORT],
612  }
613  return self.async_update_reload_and_abortasync_update_reload_and_abort(
614  reconfigure_entry,
615  data=new_data,
616  options=new_options,
617  reload_even_if_entry_is_unchanged=False,
618  )
619 
620  return self.async_show_formasync_show_formasync_show_form(
621  step_id="reconfigure",
622  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(
623  DATA_SCHEMA_EDIT_CONTROLLER, suggested_values
624  ),
625  errors=errors,
626  )
627 
628  async def async_step_user(
629  self, user_input: dict[str, Any] | None = None
630  ) -> ConfigFlowResult:
631  """Handle a flow initialized by the user."""
632  errors = {}
633  if user_input:
634  try:
635  await validate_add_controller(self, user_input)
636  except SchemaFlowError as err:
637  errors["base"] = str(err)
638  else:
639  self._async_abort_entries_match_async_abort_entries_match(
640  {CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]}
641  )
642  name = user_input.pop(CONF_NAME)
643  password = user_input.pop(CONF_PASSWORD, None)
644  username = user_input.pop(CONF_USERNAME, None)
645  user_input |= {CONF_DIMMERS: [], CONF_KEYPADS: []}
646  return self.async_create_entryasync_create_entryasync_create_entry(
647  title=name,
648  data={CONF_PASSWORD: password, CONF_USERNAME: username},
649  options=user_input,
650  )
651 
652  return self.async_show_formasync_show_formasync_show_form(
653  step_id="user",
654  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(
655  DATA_SCHEMA_ADD_CONTROLLER, user_input
656  ),
657  errors=errors,
658  )
659 
660  @staticmethod
661  @callback
662  def async_get_options_flow(config_entry: ConfigEntry) -> SchemaOptionsFlowHandler:
663  """Options flow handler for Lutron Homeworks."""
664  return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
dict[str, Any] _validate_edit_controller(self, dict[str, Any] user_input, ConfigEntry reconfigure_entry)
Definition: config_flow.py:562
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)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=None)
ConfigFlowResult async_update_reload_and_abort(self, ConfigEntry entry, *str|None|UndefinedType unique_id=UNDEFINED, str|UndefinedType title=UNDEFINED, Mapping[str, Any]|UndefinedType data=UNDEFINED, Mapping[str, Any]|UndefinedType data_updates=UNDEFINED, Mapping[str, Any]|UndefinedType options=UNDEFINED, str|UndefinedType reason=UNDEFINED, bool reload_even_if_entry_is_unchanged=True)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=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)
OptionsFlow async_get_options_flow(ConfigEntry config_entry)
str
vol.Schema add_suggested_values_to_schema(self, vol.Schema data_schema, Mapping[str, Any]|None suggested_values)
_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)
None _try_connection(dict[str, Any] user_input)
Definition: config_flow.py:139
vol.Schema get_remove_button_schema(SchemaCommonFlowHandler handler)
Definition: config_flow.py:347
dict[str, Any] validate_select_keypad_light(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:300
dict[str, Any] validate_button_edit(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:325
dict[str, Any] validate_remove_keypad_light(SchemaCommonFlowHandler handler, dict[str, Any] user_input, *str key)
Definition: config_flow.py:413
dict[str, Any] validate_light_edit(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:338
dict[str, Any] validate_remove_button(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:381
dict[str, Any] validate_add_light(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:234
dict[str, Any] get_edit_button_suggested_values(SchemaCommonFlowHandler handler)
Definition: config_flow.py:308
vol.Schema get_select_button_schema(SchemaCommonFlowHandler handler)
Definition: config_flow.py:245
dict[str, Any] validate_add_keypad(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:221
vol.Schema get_select_light_schema(SchemaCommonFlowHandler handler)
Definition: config_flow.py:276
dict[str, Any] validate_select_button(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:292
None _validate_credentials(dict[str, Any] user_input)
Definition: config_flow.py:107
vol.Schema get_remove_keypad_light_schema(SchemaCommonFlowHandler handler, *str key)
Definition: config_flow.py:365
None _validate_address(SchemaCommonFlowHandler handler, str addr)
Definition: config_flow.py:179
dict[str, Any] get_edit_light_suggested_values(SchemaCommonFlowHandler handler)
Definition: config_flow.py:317
None _validate_button_number(SchemaCommonFlowHandler handler, int number)
Definition: config_flow.py:194
vol.Schema get_select_keypad_schema(SchemaCommonFlowHandler handler)
Definition: config_flow.py:262
dict[str, Any] validate_add_button(SchemaCommonFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:206
dict[str, Any] validate_add_controller(ConfigFlow|SchemaOptionsFlowHandler handler, dict[str, Any] user_input)
Definition: config_flow.py:115
str calculate_unique_id(str controller_id, str addr, int idx)
Definition: util.py:4
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
HomeAssistant async_get_hass()
Definition: core.py:286