Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Ukraine Alarm."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import TYPE_CHECKING, Any
7 
8 import aiohttp
9 from uasiren.client import Client
10 import voluptuous as vol
11 
12 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
13 from homeassistant.const import CONF_NAME, CONF_REGION
14 from homeassistant.helpers.aiohttp_client import async_get_clientsession
15 
16 from .const import DOMAIN
17 
18 _LOGGER = logging.getLogger(__name__)
19 
20 
21 class UkraineAlarmConfigFlow(ConfigFlow, domain=DOMAIN):
22  """Config flow for Ukraine Alarm."""
23 
24  VERSION = 1
25 
26  def __init__(self) -> None:
27  """Initialize a new UkraineAlarmConfigFlow."""
28  self.statesstates: list[dict[str, Any]] | None = None
29  self.selected_regionselected_region: dict[str, Any] | None = None
30 
31  async def async_step_user(
32  self, user_input: dict[str, Any] | None = None
33  ) -> ConfigFlowResult:
34  """Handle a flow initialized by the user."""
35 
36  if len(self._async_current_entries_async_current_entries()) == 5:
37  return self.async_abortasync_abortasync_abort(reason="max_regions")
38 
39  if not self.statesstates:
40  websession = async_get_clientsession(self.hass)
41  reason = None
42  unknown_err_msg = None
43  try:
44  regions = await Client(websession).get_regions()
45  except aiohttp.ClientResponseError as ex:
46  if ex.status == 429:
47  reason = "rate_limit"
48  else:
49  reason = "unknown"
50  unknown_err_msg = str(ex)
51  except aiohttp.ClientConnectionError:
52  reason = "cannot_connect"
53  except aiohttp.ClientError as ex:
54  reason = "unknown"
55  unknown_err_msg = str(ex)
56  except TimeoutError:
57  reason = "timeout"
58 
59  if not reason and not regions:
60  reason = "unknown"
61  unknown_err_msg = "no regions returned"
62 
63  if unknown_err_msg:
64  _LOGGER.error("Failed to connect to the service: %s", unknown_err_msg)
65 
66  if reason:
67  return self.async_abortasync_abortasync_abort(reason=reason)
68  self.statesstates = regions["states"]
69 
70  return await self._handle_pick_region_handle_pick_region("user", "district", user_input)
71 
73  self, user_input: dict[str, str] | None = None
74  ) -> ConfigFlowResult:
75  """Handle user-chosen district."""
76  return await self._handle_pick_region_handle_pick_region("district", "community", user_input)
77 
79  self, user_input: dict[str, str] | None = None
80  ) -> ConfigFlowResult:
81  """Handle user-chosen community."""
82  return await self._handle_pick_region_handle_pick_region("community", None, user_input, True)
83 
85  self,
86  step_id: str,
87  next_step: str | None,
88  user_input: dict[str, str] | None,
89  last_step: bool = False,
90  ) -> ConfigFlowResult:
91  """Handle picking a (sub)region."""
92  if self.selected_regionselected_region:
93  source = self.selected_regionselected_region["regionChildIds"]
94  else:
95  source = self.statesstates
96 
97  if user_input is not None:
98  # Only offer to browse subchildren if picked region wasn't the previously picked one
99  if (
100  not self.selected_regionselected_region
101  or user_input[CONF_REGION] != self.selected_regionselected_region["regionId"]
102  ):
103  self.selected_regionselected_region = _find(source, user_input[CONF_REGION])
104 
105  if (
106  next_step
107  and self.selected_regionselected_region
108  and self.selected_regionselected_region["regionChildIds"]
109  ):
110  return await getattr(self, f"async_step_{next_step}")()
111 
112  return await self._async_finish_flow_async_finish_flow()
113 
114  regions = {}
115  if self.selected_regionselected_region:
116  regions[self.selected_regionselected_region["regionId"]] = self.selected_regionselected_region[
117  "regionName"
118  ]
119 
120  regions.update(_make_regions_object(source))
121 
122  schema = vol.Schema(
123  {
124  vol.Required(CONF_REGION): vol.In(regions),
125  }
126  )
127 
128  return self.async_show_formasync_show_formasync_show_form(
129  step_id=step_id, data_schema=schema, last_step=last_step
130  )
131 
132  async def _async_finish_flow(self) -> ConfigFlowResult:
133  """Finish the setup."""
134  if TYPE_CHECKING:
135  assert self.selected_regionselected_region is not None
136  await self.async_set_unique_idasync_set_unique_id(self.selected_regionselected_region["regionId"])
137  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
138 
139  return self.async_create_entryasync_create_entryasync_create_entry(
140  title=self.selected_regionselected_region["regionName"],
141  data={
142  CONF_REGION: self.selected_regionselected_region["regionId"],
143  CONF_NAME: self.selected_regionselected_region["regionName"],
144  },
145  )
146 
147 
148 def _find(regions: list[dict[str, Any]], region_id):
149  return next((region for region in regions if region["regionId"] == region_id), None)
150 
151 
152 def _make_regions_object(regions: list[dict[str, Any]]) -> dict[str, str]:
153  regions = sorted(regions, key=lambda region: region["regionName"].lower())
154  return {region["regionId"]: region["regionName"] for region in regions}
ConfigFlowResult _handle_pick_region(self, str step_id, str|None next_step, dict[str, str]|None user_input, bool last_step=False)
Definition: config_flow.py:90
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:33
ConfigFlowResult async_step_community(self, dict[str, str]|None user_input=None)
Definition: config_flow.py:80
ConfigFlowResult async_step_district(self, dict[str, str]|None user_input=None)
Definition: config_flow.py:74
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)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=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)
str
_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)
def _find(list[dict[str, Any]] regions, region_id)
Definition: config_flow.py:148
dict[str, str] _make_regions_object(list[dict[str, Any]] regions)
Definition: config_flow.py:152
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)