Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for NASweb integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 import voluptuous as vol
9 from webio_api import WebioAPI
10 from webio_api.api_client import AuthError
11 
12 from homeassistant import config_entries
13 from homeassistant.config_entries import ConfigFlowResult
14 from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME
15 from homeassistant.core import HomeAssistant
16 from homeassistant.data_entry_flow import AbortFlow
17 from homeassistant.exceptions import HomeAssistantError
18 from homeassistant.helpers.network import NoURLAvailableError
19 
20 from .const import DOMAIN
21 from .coordinator import NASwebCoordinator
22 from .nasweb_data import NASwebData
23 
24 NASWEB_SCHEMA_IMG_URL = (
25  "https://home-assistant.io/images/integrations/nasweb/nasweb_scheme.png"
26 )
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 STEP_USER_DATA_SCHEMA = vol.Schema(
31  {
32  vol.Required(CONF_HOST): str,
33  vol.Required(CONF_USERNAME): str,
34  vol.Required(CONF_PASSWORD): str,
35  }
36 )
37 
38 
39 async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]:
40  """Validate user-provided data."""
41  webio_api = WebioAPI(data[CONF_HOST], data[CONF_USERNAME], data[CONF_PASSWORD])
42  if not await webio_api.check_connection():
43  raise CannotConnect
44  try:
45  await webio_api.refresh_device_info()
46  except AuthError as e:
47  raise InvalidAuth from e
48 
49  nasweb_data = NASwebData()
50  nasweb_data.initialize(hass)
51  try:
52  webio_serial = webio_api.get_serial_number()
53  if webio_serial is None:
54  raise MissingNASwebData("Device serial number is not available")
55 
56  coordinator = NASwebCoordinator(hass, webio_api)
57  webhook_url = nasweb_data.get_webhook_url(hass)
58  nasweb_data.notify_coordinator.add_coordinator(webio_serial, coordinator)
59  subscription = await webio_api.status_subscription(webhook_url, True)
60  if not subscription:
61  nasweb_data.notify_coordinator.remove_coordinator(webio_serial)
62  raise MissingNASwebData(
63  "Failed to subscribe for status updates from device"
64  )
65 
66  result = await nasweb_data.notify_coordinator.check_connection(webio_serial)
67  nasweb_data.notify_coordinator.remove_coordinator(webio_serial)
68  if not result:
69  if subscription:
70  await webio_api.status_subscription(webhook_url, False)
71  raise MissingNASwebStatus("Did not receive status from device")
72 
73  name = webio_api.get_name()
74  finally:
75  nasweb_data.deinitialize(hass)
76  return {"title": name, CONF_UNIQUE_ID: webio_serial}
77 
78 
80  """Handle a config flow for NASweb."""
81 
82  VERSION = 1
83 
84  async def async_step_user(
85  self, user_input: dict[str, Any] | None = None
86  ) -> ConfigFlowResult:
87  """Handle the initial step."""
88  errors: dict[str, str] = {}
89  if user_input is not None:
90  try:
91  info = await validate_input(self.hass, user_input)
92  await self.async_set_unique_idasync_set_unique_id(info[CONF_UNIQUE_ID])
93  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
94  except CannotConnect:
95  errors["base"] = "cannot_connect"
96  except InvalidAuth:
97  errors["base"] = "invalid_auth"
98  except NoURLAvailableError:
99  errors["base"] = "missing_internal_url"
100  except MissingNASwebData:
101  errors["base"] = "missing_nasweb_data"
102  except MissingNASwebStatus:
103  errors["base"] = "missing_status"
104  except AbortFlow:
105  raise
106  except Exception: # pylint: disable=broad-except
107  _LOGGER.exception("Unexpected exception")
108  errors["base"] = "unknown"
109  else:
110  return self.async_create_entryasync_create_entryasync_create_entry(title=info["title"], data=user_input)
111 
112  return self.async_show_formasync_show_formasync_show_form(
113  step_id="user",
114  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(
115  STEP_USER_DATA_SCHEMA, user_input
116  ),
117  errors=errors,
118  description_placeholders={
119  "nasweb_schema_img": '<img src="' + NASWEB_SCHEMA_IMG_URL + '"/><br>',
120  },
121  )
122 
123 
125  """Error to indicate we cannot connect."""
126 
127 
129  """Error to indicate there is invalid auth."""
130 
131 
133  """Error to indicate missing information from NASweb."""
134 
135 
137  """Error to indicate there was no status received from NASweb."""
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:86
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_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)
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)
dict[str, Any] validate_input(HomeAssistant hass, dict[str, Any] data)
Definition: config_flow.py:39