Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Plaato."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from pyplaato.plaato import PlaatoDeviceType
8 import voluptuous as vol
9 
10 from homeassistant.components import cloud, webhook
11 from homeassistant.config_entries import (
12  ConfigEntry,
13  ConfigFlow,
14  ConfigFlowResult,
15  OptionsFlow,
16 )
17 from homeassistant.const import CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_WEBHOOK_ID
18 from homeassistant.core import callback
20 
21 from .const import (
22  CONF_CLOUDHOOK,
23  CONF_DEVICE_NAME,
24  CONF_DEVICE_TYPE,
25  CONF_USE_WEBHOOK,
26  DEFAULT_SCAN_INTERVAL,
27  DOCS_URL,
28  DOMAIN,
29  PLACEHOLDER_DEVICE_NAME,
30  PLACEHOLDER_DEVICE_TYPE,
31  PLACEHOLDER_DOCS_URL,
32  PLACEHOLDER_WEBHOOK_URL,
33 )
34 
35 
36 class PlaatoConfigFlow(ConfigFlow, domain=DOMAIN):
37  """Handles a Plaato config flow."""
38 
39  VERSION = 1
40 
41  def __init__(self) -> None:
42  """Initialize."""
43  self._init_info: dict[str, Any] = {}
44 
45  async def async_step_user(
46  self, user_input: dict[str, Any] | None = None
47  ) -> ConfigFlowResult:
48  """Handle user step."""
49 
50  if user_input is not None:
51  self._init_info[CONF_DEVICE_TYPE] = PlaatoDeviceType(
52  user_input[CONF_DEVICE_TYPE]
53  )
54  self._init_info[CONF_DEVICE_NAME] = user_input[CONF_DEVICE_NAME]
55 
56  return await self.async_step_api_methodasync_step_api_method()
57 
58  return self.async_show_formasync_show_formasync_show_form(
59  step_id="user",
60  data_schema=vol.Schema(
61  {
62  vol.Required(
63  CONF_DEVICE_NAME,
64  default=self._init_info.get(CONF_DEVICE_NAME, None),
65  ): str,
66  vol.Required(
67  CONF_DEVICE_TYPE,
68  default=self._init_info.get(CONF_DEVICE_TYPE, None),
69  ): vol.In(list(PlaatoDeviceType)),
70  }
71  ),
72  )
73 
75  self, user_input: dict[str, Any] | None = None
76  ) -> ConfigFlowResult:
77  """Handle device type step."""
78 
79  device_type = self._init_info[CONF_DEVICE_TYPE]
80 
81  if user_input is not None:
82  token = user_input.get(CONF_TOKEN, None)
83  use_webhook = user_input.get(CONF_USE_WEBHOOK, False)
84 
85  if not token and not use_webhook:
86  errors = {"base": PlaatoConfigFlow._get_error(device_type)}
87  return await self._show_api_method_form_show_api_method_form(device_type, errors)
88 
89  self._init_info[CONF_USE_WEBHOOK] = use_webhook
90  self._init_info[CONF_TOKEN] = token
91  return await self.async_step_webhookasync_step_webhook()
92 
93  return await self._show_api_method_form_show_api_method_form(device_type)
94 
95  async def async_step_webhook(
96  self, user_input: dict[str, Any] | None = None
97  ) -> ConfigFlowResult:
98  """Validate config step."""
99 
100  use_webhook = self._init_info[CONF_USE_WEBHOOK]
101 
102  if use_webhook and user_input is None:
103  try:
104  webhook_id, webhook_url, cloudhook = await self._get_webhook_id_get_webhook_id()
106  return self.async_abortasync_abortasync_abort(reason="cloud_not_connected")
107  self._init_info[CONF_WEBHOOK_ID] = webhook_id
108  self._init_info[CONF_CLOUDHOOK] = cloudhook
109 
110  return self.async_show_formasync_show_formasync_show_form(
111  step_id="webhook",
112  description_placeholders={
113  PLACEHOLDER_WEBHOOK_URL: webhook_url,
114  PLACEHOLDER_DOCS_URL: DOCS_URL,
115  },
116  )
117 
118  return await self._async_create_entry_async_create_entry()
119 
120  async def _async_create_entry(self):
121  """Create the entry step."""
122 
123  webhook_id = self._init_info.get(CONF_WEBHOOK_ID, None)
124  auth_token = self._init_info[CONF_TOKEN]
125  device_name = self._init_info[CONF_DEVICE_NAME]
126  device_type = self._init_info[CONF_DEVICE_TYPE]
127 
128  unique_id = auth_token if auth_token else webhook_id
129 
130  await self.async_set_unique_idasync_set_unique_id(unique_id)
131  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
132 
133  return self.async_create_entryasync_create_entryasync_create_entry(
134  title=device_type.name,
135  data=self._init_info,
136  description_placeholders={
137  PLACEHOLDER_DEVICE_TYPE: device_type.name,
138  PLACEHOLDER_DEVICE_NAME: device_name,
139  },
140  )
141 
143  self, device_type: PlaatoDeviceType, errors: dict[str, str] | None = None
144  ) -> ConfigFlowResult:
145  data_schema = vol.Schema({vol.Optional(CONF_TOKEN, default=""): str})
146 
147  if device_type == PlaatoDeviceType.Airlock:
148  data_schema = data_schema.extend(
149  {vol.Optional(CONF_USE_WEBHOOK, default=False): bool}
150  )
151 
152  return self.async_show_formasync_show_formasync_show_form(
153  step_id="api_method",
154  data_schema=data_schema,
155  errors=errors,
156  description_placeholders={PLACEHOLDER_DEVICE_TYPE: device_type.name},
157  )
158 
159  async def _get_webhook_id(self):
160  """Generate webhook ID."""
161  webhook_id = webhook.async_generate_id()
162  if cloud.async_active_subscription(self.hass):
163  webhook_url = await cloud.async_create_cloudhook(self.hass, webhook_id)
164  cloudhook = True
165  else:
166  webhook_url = webhook.async_generate_url(self.hass, webhook_id)
167  cloudhook = False
168 
169  return webhook_id, webhook_url, cloudhook
170 
171  @staticmethod
172  def _get_error(device_type: PlaatoDeviceType):
173  if device_type == PlaatoDeviceType.Airlock:
174  return "no_api_method"
175  return "no_auth_token"
176 
177  @staticmethod
178  @callback
180  config_entry: ConfigEntry,
181  ) -> PlaatoOptionsFlowHandler:
182  """Get the options flow for this handler."""
183  return PlaatoOptionsFlowHandler()
184 
185 
187  """Handle Plaato options."""
188 
189  async def async_step_init(self, user_input: None = None) -> ConfigFlowResult:
190  """Manage the options."""
191  use_webhook = self.config_entryconfig_entryconfig_entry.data.get(CONF_USE_WEBHOOK, False)
192  if use_webhook:
193  return await self.async_step_webhookasync_step_webhook()
194 
195  return await self.async_step_userasync_step_user()
196 
197  async def async_step_user(
198  self, user_input: dict[str, Any] | None = None
199  ) -> ConfigFlowResult:
200  """Manage the options."""
201  if user_input is not None:
202  return self.async_create_entryasync_create_entry(title="", data=user_input)
203 
204  return self.async_show_formasync_show_form(
205  step_id="user",
206  data_schema=vol.Schema(
207  {
208  vol.Optional(
209  CONF_SCAN_INTERVAL,
210  default=self.config_entryconfig_entryconfig_entry.options.get(
211  CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
212  ),
213  ): cv.positive_int
214  }
215  ),
216  )
217 
219  self, user_input: dict[str, Any] | None = None
220  ) -> ConfigFlowResult:
221  """Manage the options for webhook device."""
222  if user_input is not None:
223  return self.async_create_entryasync_create_entry(title="", data=user_input)
224 
225  webhook_id = self.config_entryconfig_entryconfig_entry.data.get(CONF_WEBHOOK_ID, None)
226  webhook_url = (
227  ""
228  if webhook_id is None
229  else webhook.async_generate_url(self.hass, webhook_id)
230  )
231 
232  return self.async_show_formasync_show_form(
233  step_id="webhook",
234  description_placeholders={PLACEHOLDER_WEBHOOK_URL: webhook_url},
235  )
ConfigFlowResult _show_api_method_form(self, PlaatoDeviceType device_type, dict[str, str]|None errors=None)
Definition: config_flow.py:144
ConfigFlowResult async_step_webhook(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:97
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:47
ConfigFlowResult async_step_api_method(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:76
PlaatoOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
Definition: config_flow.py:181
ConfigFlowResult async_step_webhook(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:220
ConfigFlowResult async_step_init(self, None user_input=None)
Definition: config_flow.py:189
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:199
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)
ConfigFlowResult async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=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)
None config_entry(self, ConfigEntry value)
_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)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88