Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Google Maps Travel Time integration."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 import voluptuous as vol
8 
10  ConfigEntry,
11  ConfigFlow,
12  ConfigFlowResult,
13  OptionsFlow,
14 )
15 from homeassistant.const import CONF_API_KEY, CONF_LANGUAGE, CONF_MODE, CONF_NAME
16 from homeassistant.core import HomeAssistant, callback
19  SelectSelector,
20  SelectSelectorConfig,
21  SelectSelectorMode,
22 )
23 from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
24 
25 from .const import (
26  ALL_LANGUAGES,
27  ARRIVAL_TIME,
28  AVOID_OPTIONS,
29  CONF_ARRIVAL_TIME,
30  CONF_AVOID,
31  CONF_DEPARTURE_TIME,
32  CONF_DESTINATION,
33  CONF_ORIGIN,
34  CONF_TIME,
35  CONF_TIME_TYPE,
36  CONF_TRAFFIC_MODEL,
37  CONF_TRANSIT_MODE,
38  CONF_TRANSIT_ROUTING_PREFERENCE,
39  CONF_UNITS,
40  DEFAULT_NAME,
41  DEPARTURE_TIME,
42  DOMAIN,
43  TIME_TYPES,
44  TRAFFIC_MODELS,
45  TRANSIT_PREFS,
46  TRANSPORT_TYPES,
47  TRAVEL_MODES,
48  UNITS,
49  UNITS_IMPERIAL,
50  UNITS_METRIC,
51 )
52 from .helpers import InvalidApiKeyException, UnknownException, validate_config_entry
53 
54 RECONFIGURE_SCHEMA = vol.Schema(
55  {
56  vol.Required(CONF_API_KEY): cv.string,
57  vol.Required(CONF_DESTINATION): cv.string,
58  vol.Required(CONF_ORIGIN): cv.string,
59  }
60 )
61 
62 CONFIG_SCHEMA = RECONFIGURE_SCHEMA.extend(
63  {
64  vol.Required(CONF_NAME, default=DEFAULT_NAME): cv.string,
65  }
66 )
67 
68 OPTIONS_SCHEMA = vol.Schema(
69  {
70  vol.Required(CONF_MODE): SelectSelector(
72  options=TRAVEL_MODES,
73  sort=True,
74  mode=SelectSelectorMode.DROPDOWN,
75  translation_key=CONF_MODE,
76  )
77  ),
78  vol.Optional(CONF_LANGUAGE): SelectSelector(
80  options=sorted(ALL_LANGUAGES),
81  mode=SelectSelectorMode.DROPDOWN,
82  translation_key=CONF_LANGUAGE,
83  )
84  ),
85  vol.Optional(CONF_AVOID): SelectSelector(
87  options=AVOID_OPTIONS,
88  sort=True,
89  mode=SelectSelectorMode.DROPDOWN,
90  translation_key=CONF_AVOID,
91  )
92  ),
93  vol.Required(CONF_UNITS): SelectSelector(
95  options=UNITS,
96  sort=True,
97  mode=SelectSelectorMode.DROPDOWN,
98  translation_key=CONF_UNITS,
99  )
100  ),
101  vol.Required(CONF_TIME_TYPE): SelectSelector(
103  options=TIME_TYPES,
104  sort=True,
105  mode=SelectSelectorMode.DROPDOWN,
106  translation_key=CONF_TIME_TYPE,
107  )
108  ),
109  vol.Optional(CONF_TIME, default=""): cv.string,
110  vol.Optional(CONF_TRAFFIC_MODEL): SelectSelector(
112  options=TRAFFIC_MODELS,
113  sort=True,
114  mode=SelectSelectorMode.DROPDOWN,
115  translation_key=CONF_TRAFFIC_MODEL,
116  )
117  ),
118  vol.Optional(CONF_TRANSIT_MODE): SelectSelector(
120  options=TRANSPORT_TYPES,
121  sort=True,
122  mode=SelectSelectorMode.DROPDOWN,
123  translation_key=CONF_TRANSIT_MODE,
124  )
125  ),
126  vol.Optional(CONF_TRANSIT_ROUTING_PREFERENCE): SelectSelector(
128  options=TRANSIT_PREFS,
129  sort=True,
130  mode=SelectSelectorMode.DROPDOWN,
131  translation_key=CONF_TRANSIT_ROUTING_PREFERENCE,
132  )
133  ),
134  }
135 )
136 
137 
138 def default_options(hass: HomeAssistant) -> dict[str, str]:
139  """Get the default options."""
140  return {
141  CONF_MODE: "driving",
142  CONF_UNITS: (
143  UNITS_IMPERIAL if hass.config.units is US_CUSTOMARY_SYSTEM else UNITS_METRIC
144  ),
145  }
146 
147 
149  """Handle an options flow for Google Travel Time."""
150 
151  async def async_step_init(self, user_input=None) -> ConfigFlowResult:
152  """Handle the initial step."""
153  if user_input is not None:
154  time_type = user_input.pop(CONF_TIME_TYPE)
155  if time := user_input.pop(CONF_TIME, None):
156  if time_type == ARRIVAL_TIME:
157  user_input[CONF_ARRIVAL_TIME] = time
158  else:
159  user_input[CONF_DEPARTURE_TIME] = time
160  return self.async_create_entryasync_create_entry(
161  title="",
162  data=user_input,
163  )
164 
165  options = self.config_entryconfig_entryconfig_entry.options.copy()
166  if CONF_ARRIVAL_TIME in self.config_entryconfig_entryconfig_entry.options:
167  options[CONF_TIME_TYPE] = ARRIVAL_TIME
168  options[CONF_TIME] = self.config_entryconfig_entryconfig_entry.options[CONF_ARRIVAL_TIME]
169  else:
170  options[CONF_TIME_TYPE] = DEPARTURE_TIME
171  options[CONF_TIME] = self.config_entryconfig_entryconfig_entry.options.get(CONF_DEPARTURE_TIME, "")
172 
173  return self.async_show_formasync_show_form(
174  step_id="init",
175  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(OPTIONS_SCHEMA, options),
176  )
177 
178 
179 async def validate_input(
180  hass: HomeAssistant, user_input: dict[str, Any]
181 ) -> dict[str, str] | None:
182  """Validate the user input allows us to connect."""
183  try:
184  await hass.async_add_executor_job(
185  validate_config_entry,
186  hass,
187  user_input[CONF_API_KEY],
188  user_input[CONF_ORIGIN],
189  user_input[CONF_DESTINATION],
190  )
191  except InvalidApiKeyException:
192  return {"base": "invalid_auth"}
193  except TimeoutError:
194  return {"base": "timeout_connect"}
195  except UnknownException:
196  return {"base": "cannot_connect"}
197 
198  return None
199 
200 
202  """Handle a config flow for Google Maps Travel Time."""
203 
204  VERSION = 1
205 
206  @staticmethod
207  @callback
209  config_entry: ConfigEntry,
210  ) -> GoogleOptionsFlow:
211  """Get the options flow for this handler."""
212  return GoogleOptionsFlow()
213 
214  async def async_step_user(self, user_input=None) -> ConfigFlowResult:
215  """Handle the initial step."""
216  errors: dict[str, str] | None = None
217  user_input = user_input or {}
218  if user_input:
219  errors = await validate_input(self.hass, user_input)
220  if not errors:
221  return self.async_create_entryasync_create_entryasync_create_entry(
222  title=user_input.get(CONF_NAME, DEFAULT_NAME),
223  data=user_input,
224  options=default_options(self.hass),
225  )
226 
227  return self.async_show_formasync_show_formasync_show_form(
228  step_id="user",
229  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(CONFIG_SCHEMA, user_input),
230  errors=errors,
231  )
232 
234  self, user_input: dict[str, Any] | None = None
235  ) -> ConfigFlowResult:
236  """Handle reconfiguration."""
237  errors: dict[str, str] | None = None
238  if user_input is not None:
239  errors = await validate_input(self.hass, user_input)
240  if not errors:
241  return self.async_update_reload_and_abortasync_update_reload_and_abort(
242  self._get_reconfigure_entry_get_reconfigure_entry(), data=user_input
243  )
244 
245  return self.async_show_formasync_show_formasync_show_form(
246  step_id="reconfigure",
247  data_schema=self.add_suggested_values_to_schemaadd_suggested_values_to_schema(
248  RECONFIGURE_SCHEMA, self._get_reconfigure_entry_get_reconfigure_entry().data
249  ),
250  errors=errors,
251  )
ConfigFlowResult async_step_reconfigure(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:235
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_update_reload_and_abort(self, ConfigEntry entry, *str|None|UndefinedType unique_id=UNDEFINED, str|UndefinedType title=UNDEFINED, Mapping[str, Any]|UndefinedType data=UNDEFINED, Mapping[str, Any]|UndefinedType data_updates=UNDEFINED, Mapping[str, Any]|UndefinedType options=UNDEFINED, str|UndefinedType reason=UNDEFINED, bool reload_even_if_entry_is_unchanged=True)
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)
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, str] default_options(HomeAssistant hass)
Definition: config_flow.py:138
dict[str, str]|None validate_input(HomeAssistant hass, dict[str, Any] user_input)
Definition: config_flow.py:181