Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for swiss_public_transport."""
2 
3 import logging
4 from typing import Any
5 
6 from opendata_transport import OpendataTransport
7 from opendata_transport.exceptions import (
8  OpendataTransportConnectionError,
9  OpendataTransportError,
10 )
11 import voluptuous as vol
12 
13 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
14 from homeassistant.helpers.aiohttp_client import async_get_clientsession
17  DurationSelector,
18  SelectSelector,
19  SelectSelectorConfig,
20  SelectSelectorMode,
21  TextSelector,
22  TextSelectorConfig,
23  TextSelectorType,
24  TimeSelector,
25 )
26 
27 from .const import (
28  CONF_DESTINATION,
29  CONF_START,
30  CONF_TIME_FIXED,
31  CONF_TIME_MODE,
32  CONF_TIME_OFFSET,
33  CONF_TIME_STATION,
34  CONF_VIA,
35  DEFAULT_TIME_MODE,
36  DEFAULT_TIME_STATION,
37  DOMAIN,
38  IS_ARRIVAL_OPTIONS,
39  MAX_VIA,
40  PLACEHOLDERS,
41  TIME_MODE_OPTIONS,
42 )
43 from .helper import offset_opendata, unique_id_from_config
44 
45 USER_DATA_SCHEMA = vol.Schema(
46  {
47  vol.Required(CONF_START): cv.string,
48  vol.Optional(CONF_VIA): TextSelector(
50  type=TextSelectorType.TEXT,
51  multiple=True,
52  ),
53  ),
54  vol.Required(CONF_DESTINATION): cv.string,
55  vol.Optional(CONF_TIME_MODE, default=DEFAULT_TIME_MODE): SelectSelector(
57  options=TIME_MODE_OPTIONS,
58  mode=SelectSelectorMode.DROPDOWN,
59  translation_key="time_mode",
60  ),
61  ),
62  vol.Optional(CONF_TIME_STATION, default=DEFAULT_TIME_STATION): SelectSelector(
64  options=IS_ARRIVAL_OPTIONS,
65  mode=SelectSelectorMode.DROPDOWN,
66  translation_key="time_station",
67  ),
68  ),
69  }
70 )
71 ADVANCED_TIME_DATA_SCHEMA = {vol.Optional(CONF_TIME_FIXED): TimeSelector()}
72 ADVANCED_TIME_OFFSET_DATA_SCHEMA = {vol.Optional(CONF_TIME_OFFSET): DurationSelector()}
73 
74 
75 _LOGGER = logging.getLogger(__name__)
76 
77 
79  """Swiss public transport config flow."""
80 
81  VERSION = 3
82  MINOR_VERSION = 1
83 
84  user_input: dict[str, Any]
85 
86  async def async_step_user(
87  self, user_input: dict[str, Any] | None = None
88  ) -> ConfigFlowResult:
89  """Async user step to set up the connection."""
90  errors: dict[str, str] = {}
91  if user_input is not None:
92  if CONF_VIA in user_input and len(user_input[CONF_VIA]) > MAX_VIA:
93  errors["base"] = "too_many_via_stations"
94  else:
95  err = await self.fetch_connectionsfetch_connections(user_input)
96  if err:
97  errors["base"] = err
98  else:
99  self.user_inputuser_input = user_input
100  if user_input[CONF_TIME_MODE] == "fixed":
101  return await self.async_step_time_fixedasync_step_time_fixed()
102  if user_input[CONF_TIME_MODE] == "offset":
103  return await self.async_step_time_offsetasync_step_time_offset()
104 
105  unique_id = unique_id_from_config(user_input)
106  await self.async_set_unique_idasync_set_unique_id(unique_id)
107  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
108  return self.async_create_entryasync_create_entryasync_create_entry(
109  title=unique_id,
110  data=user_input,
111  )
112 
113  return self.async_show_formasync_show_formasync_show_form(
114  step_id="user",
115  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(
116  data_schema=USER_DATA_SCHEMA,
117  suggested_values=user_input,
118  ),
119  errors=errors,
120  description_placeholders=PLACEHOLDERS,
121  )
122 
124  self, time_input: dict[str, Any] | None = None
125  ) -> ConfigFlowResult:
126  """Async time step to set up the connection."""
127  return await self._async_step_time_mode_async_step_time_mode(
128  CONF_TIME_FIXED, vol.Schema(ADVANCED_TIME_DATA_SCHEMA), time_input
129  )
130 
132  self, time_offset_input: dict[str, Any] | None = None
133  ) -> ConfigFlowResult:
134  """Async time offset step to set up the connection."""
135  return await self._async_step_time_mode_async_step_time_mode(
136  CONF_TIME_OFFSET,
137  vol.Schema(ADVANCED_TIME_OFFSET_DATA_SCHEMA),
138  time_offset_input,
139  )
140 
142  self,
143  step_id: str,
144  time_mode_schema: vol.Schema,
145  time_mode_input: dict[str, Any] | None = None,
146  ) -> ConfigFlowResult:
147  """Async time mode step to set up the connection."""
148  errors: dict[str, str] = {}
149  if time_mode_input is not None:
150  unique_id = unique_id_from_config({**self.user_inputuser_input, **time_mode_input})
151  await self.async_set_unique_idasync_set_unique_id(unique_id)
152  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
153 
154  err = await self.fetch_connectionsfetch_connections(
155  {**self.user_inputuser_input, **time_mode_input},
156  time_mode_input.get(CONF_TIME_OFFSET),
157  )
158  if err:
159  errors["base"] = err
160  else:
161  return self.async_create_entryasync_create_entryasync_create_entry(
162  title=unique_id,
163  data={**self.user_inputuser_input, **time_mode_input},
164  )
165 
166  return self.async_show_formasync_show_formasync_show_form(
167  step_id=step_id,
168  data_schema=time_mode_schema,
169  errors=errors,
170  description_placeholders=PLACEHOLDERS,
171  )
172 
173  async def fetch_connections(
174  self, input: dict[str, Any], time_offset: dict[str, int] | None = None
175  ) -> str | None:
176  """Fetch the connections and advancedly return an error."""
177  try:
178  session = async_get_clientsession(self.hass)
179  opendata = OpendataTransport(
180  input[CONF_START],
181  input[CONF_DESTINATION],
182  session,
183  via=input.get(CONF_VIA),
184  time=input.get(CONF_TIME_FIXED),
185  )
186  if time_offset:
187  offset_opendata(opendata, time_offset)
188  await opendata.async_get_data()
189  except OpendataTransportConnectionError:
190  return "cannot_connect"
191  except OpendataTransportError:
192  return "bad_config"
193  except Exception: # pylint: disable=broad-except
194  _LOGGER.exception("Unknown error")
195  return "unknown"
196  return None
ConfigFlowResult async_step_time_offset(self, dict[str, Any]|None time_offset_input=None)
Definition: config_flow.py:133
str|None fetch_connections(self, dict[str, Any] input, dict[str, int]|None time_offset=None)
Definition: config_flow.py:175
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:88
ConfigFlowResult async_step_time_fixed(self, dict[str, Any]|None time_input=None)
Definition: config_flow.py:125
ConfigFlowResult _async_step_time_mode(self, str step_id, vol.Schema time_mode_schema, dict[str, Any]|None time_mode_input=None)
Definition: config_flow.py:146
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)
None offset_opendata(OpendataTransport opendata, dict[str, int] offset)
Definition: helper.py:22
str unique_id_from_config(MappingProxyType[str, Any]|dict[str, Any] config)
Definition: helper.py:39
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)