config_flow.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from __future__ import annotations
  2. import voluptuous as vol
  3. from homeassistant.config_entries import ConfigFlow, ConfigFlowResult, OptionsFlow
  4. from homeassistant.core import callback
  5. from homeassistant.helpers import selector
  6. from .const import DOMAIN, CONF_LOCK_ENTITY_IDS, CONF_GROUPS, CONF_GROUP_NAME
  7. class ZLockSlotsConfigFlow(ConfigFlow, domain=DOMAIN):
  8. VERSION = 1
  9. async def async_step_user(
  10. self, user_input: dict | None = None
  11. ) -> ConfigFlowResult:
  12. errors: dict[str, str] = {}
  13. if user_input is not None:
  14. lock_ids: list[str] = user_input.get(CONF_LOCK_ENTITY_IDS, [])
  15. if not lock_ids:
  16. errors[CONF_LOCK_ENTITY_IDS] = "no_locks_selected"
  17. else:
  18. title = self._make_title(lock_ids)
  19. return self.async_create_entry(title=title, data={CONF_LOCK_ENTITY_IDS: lock_ids})
  20. schema = vol.Schema({
  21. vol.Required(CONF_LOCK_ENTITY_IDS): selector.EntitySelector(
  22. selector.EntitySelectorConfig(
  23. domain="lock",
  24. integration="zwave_js",
  25. multiple=True,
  26. )
  27. ),
  28. })
  29. return self.async_show_form(
  30. step_id="user",
  31. data_schema=schema,
  32. errors=errors,
  33. )
  34. @staticmethod
  35. @callback
  36. def async_get_options_flow(config_entry) -> "ZLockSlotsOptionsFlow":
  37. return ZLockSlotsOptionsFlow(config_entry)
  38. def _make_title(self, lock_ids: list[str]) -> str:
  39. if len(lock_ids) == 1:
  40. state = self.hass.states.get(lock_ids[0])
  41. if state:
  42. return state.name
  43. return f"Z-Lock Slots ({len(lock_ids)} locks)"
  44. class ZLockSlotsOptionsFlow(OptionsFlow):
  45. def __init__(self, config_entry) -> None:
  46. self._entry = config_entry
  47. self._groups: list[dict] = list(config_entry.options.get(CONF_GROUPS, []))
  48. async def async_step_init(self, user_input=None) -> ConfigFlowResult:
  49. return self.async_show_menu(
  50. step_id="init",
  51. menu_options=["manage_locks", "add_group", "remove_group", "finish"],
  52. )
  53. async def async_step_manage_locks(self, user_input=None) -> ConfigFlowResult:
  54. errors: dict[str, str] = {}
  55. current_lock_ids: list[str] = self._entry.data.get(CONF_LOCK_ENTITY_IDS, [])
  56. if user_input is not None:
  57. new_lock_ids: list[str] = user_input.get(CONF_LOCK_ENTITY_IDS, [])
  58. if not new_lock_ids:
  59. errors[CONF_LOCK_ENTITY_IDS] = "no_locks_selected"
  60. else:
  61. removed = set(current_lock_ids) - set(new_lock_ids)
  62. if removed:
  63. self._groups = [
  64. g for g in self._groups
  65. if not all(lid in removed for lid in g.get(CONF_LOCK_ENTITY_IDS, []))
  66. ]
  67. for g in self._groups:
  68. g[CONF_LOCK_ENTITY_IDS] = [
  69. lid for lid in g.get(CONF_LOCK_ENTITY_IDS, []) if lid not in removed
  70. ]
  71. self._groups = [g for g in self._groups if g.get(CONF_LOCK_ENTITY_IDS)]
  72. self.hass.config_entries.async_update_entry(
  73. self._entry, data={CONF_LOCK_ENTITY_IDS: new_lock_ids}
  74. )
  75. return await self.async_step_init()
  76. schema = vol.Schema({
  77. vol.Required(CONF_LOCK_ENTITY_IDS, default=current_lock_ids): selector.EntitySelector(
  78. selector.EntitySelectorConfig(
  79. domain="lock",
  80. integration="zwave_js",
  81. multiple=True,
  82. )
  83. ),
  84. })
  85. return self.async_show_form(step_id="manage_locks", data_schema=schema, errors=errors)
  86. async def async_step_add_group(self, user_input=None) -> ConfigFlowResult:
  87. errors: dict[str, str] = {}
  88. lock_ids: list[str] = self._entry.data[CONF_LOCK_ENTITY_IDS]
  89. if user_input is not None:
  90. name = user_input.get(CONF_GROUP_NAME, "").strip()
  91. selected: list[str] = user_input.get(CONF_LOCK_ENTITY_IDS, [])
  92. if not name:
  93. errors[CONF_GROUP_NAME] = "group_name_required"
  94. elif any(g[CONF_GROUP_NAME] == name for g in self._groups):
  95. errors[CONF_GROUP_NAME] = "group_name_exists"
  96. elif not selected:
  97. errors[CONF_LOCK_ENTITY_IDS] = "no_locks_selected"
  98. else:
  99. self._groups.append({CONF_GROUP_NAME: name, CONF_LOCK_ENTITY_IDS: selected})
  100. return await self.async_step_init()
  101. lock_options = [
  102. selector.SelectOptionDict(
  103. value=lid,
  104. label=(self.hass.states.get(lid).name if self.hass.states.get(lid) else lid),
  105. )
  106. for lid in lock_ids
  107. ]
  108. schema = vol.Schema({
  109. vol.Required(CONF_GROUP_NAME): selector.TextSelector(),
  110. vol.Required(CONF_LOCK_ENTITY_IDS): selector.SelectSelector(
  111. selector.SelectSelectorConfig(options=lock_options, multiple=True)
  112. ),
  113. })
  114. return self.async_show_form(step_id="add_group", data_schema=schema, errors=errors)
  115. async def async_step_remove_group(self, user_input=None) -> ConfigFlowResult:
  116. if not self._groups:
  117. return await self.async_step_init()
  118. if user_input is not None:
  119. names_to_remove = set(user_input.get("groups", []))
  120. self._groups = [g for g in self._groups if g[CONF_GROUP_NAME] not in names_to_remove]
  121. return await self.async_step_init()
  122. schema = vol.Schema({
  123. vol.Required("groups"): selector.SelectSelector(
  124. selector.SelectSelectorConfig(
  125. options=[
  126. selector.SelectOptionDict(value=g[CONF_GROUP_NAME], label=g[CONF_GROUP_NAME])
  127. for g in self._groups
  128. ],
  129. multiple=True,
  130. )
  131. ),
  132. })
  133. return self.async_show_form(step_id="remove_group", data_schema=schema)
  134. async def async_step_finish(self, user_input=None) -> ConfigFlowResult:
  135. return self.async_create_entry(data={CONF_GROUPS: self._groups})