1 """Define a config flow manager for AirVisual."""
3 from __future__
import annotations
6 from collections.abc
import Mapping
9 from pyairvisual.cloud_api
import (
16 from pyairvisual.errors
import AirVisualError
17 import voluptuous
as vol
37 SchemaOptionsFlowHandler,
40 from .
import async_get_geography_id
43 CONF_INTEGRATION_TYPE,
45 INTEGRATION_TYPE_GEOGRAPHY_COORDS,
46 INTEGRATION_TYPE_GEOGRAPHY_NAME,
50 API_KEY_DATA_SCHEMA = vol.Schema({vol.Required(CONF_API_KEY): cv.string})
51 GEOGRAPHY_NAME_SCHEMA = API_KEY_DATA_SCHEMA.extend(
53 vol.Required(CONF_CITY): cv.string,
54 vol.Required(CONF_STATE): cv.string,
55 vol.Required(CONF_COUNTRY): cv.string,
58 PICK_INTEGRATION_TYPE_SCHEMA = vol.Schema(
60 vol.Required(
"type"): vol.In(
62 INTEGRATION_TYPE_GEOGRAPHY_COORDS,
63 INTEGRATION_TYPE_GEOGRAPHY_NAME,
69 OPTIONS_SCHEMA = vol.Schema(
70 {vol.Required(CONF_SHOW_ON_MAP): bool},
78 """Handle an AirVisual config flow."""
83 """Initialize the config flow."""
85 self.
_geo_id_geo_id: str |
None =
None
89 """Return the data schema for the cloud API."""
90 return API_KEY_DATA_SCHEMA.extend(
93 CONF_LATITUDE, default=self.hass.config.latitude
96 CONF_LONGITUDE, default=self.hass.config.longitude
102 self, user_input: dict[str, str], integration_type: str
103 ) -> ConfigFlowResult:
104 """Validate a Cloud API key."""
106 websession = aiohttp_client.async_get_clientsession(self.hass)
107 cloud_api = CloudAPI(user_input[CONF_API_KEY], session=websession)
111 valid_keys = self.hass.data.setdefault(
"airvisual_checked_api_keys", set())
112 valid_keys_lock = self.hass.data.setdefault(
113 "airvisual_checked_api_keys_lock", asyncio.Lock()
116 async
with valid_keys_lock:
117 if user_input[CONF_API_KEY]
not in valid_keys:
118 if integration_type == INTEGRATION_TYPE_GEOGRAPHY_COORDS:
119 coro = cloud_api.air_quality.nearest_city()
121 error_step =
"geography_by_coords"
123 coro = cloud_api.air_quality.city(
124 user_input[CONF_CITY],
125 user_input[CONF_STATE],
126 user_input[CONF_COUNTRY],
128 error_schema = GEOGRAPHY_NAME_SCHEMA
129 error_step =
"geography_by_name"
133 except (InvalidKeyError, KeyExpiredError, UnauthorizedError):
134 errors[CONF_API_KEY] =
"invalid_api_key"
135 except NotFoundError:
136 errors[CONF_CITY] =
"location_not_found"
137 except AirVisualError
as err:
139 errors[
"base"] =
"unknown"
143 step_id=error_step, data_schema=error_schema, errors=errors
146 valid_keys.add(user_input[CONF_API_KEY])
151 data_updates={CONF_API_KEY: user_input[CONF_API_KEY]},
155 title=f
"Cloud API ({self._geo_id})",
156 data={**user_input, CONF_INTEGRATION_TYPE: integration_type},
160 self, user_input: dict[str, str], integration_type: str
161 ) -> ConfigFlowResult:
162 """Handle the initialization of the integration via the cloud API."""
169 """Set the unique ID of the config flow and abort if it already exists."""
176 """Define the config flow to handle options."""
180 """Handle import of config entry version 1 data."""
181 import_source = import_data.pop(
"import_source")
182 if import_source ==
"geography_by_coords":
187 self, user_input: dict[str, str] |
None =
None
188 ) -> ConfigFlowResult:
189 """Handle the initialization of the cloud API based on latitude/longitude."""
196 user_input, INTEGRATION_TYPE_GEOGRAPHY_COORDS
200 self, user_input: dict[str, str] |
None =
None
201 ) -> ConfigFlowResult:
202 """Handle the initialization of the cloud API based on city/state/country."""
205 step_id=
"geography_by_name", data_schema=GEOGRAPHY_NAME_SCHEMA
209 user_input, INTEGRATION_TYPE_GEOGRAPHY_NAME
213 self, entry_data: Mapping[str, Any]
214 ) -> ConfigFlowResult:
215 """Handle configuration by re-auth."""
221 self, user_input: dict[str, str] |
None =
None
222 ) -> ConfigFlowResult:
223 """Handle re-auth completion."""
226 step_id=
"reauth_confirm", data_schema=API_KEY_DATA_SCHEMA
236 self, user_input: dict[str, str] |
None =
None
237 ) -> ConfigFlowResult:
238 """Handle the start of the config flow."""
241 step_id=
"user", data_schema=PICK_INTEGRATION_TYPE_SCHEMA
244 if user_input[
"type"] == INTEGRATION_TYPE_GEOGRAPHY_COORDS:
ConfigFlowResult async_step_import(self, dict[str, str] import_data)
None _async_set_unique_id(self, str unique_id)
ConfigFlowResult async_step_user(self, dict[str, str]|None user_input=None)
SchemaOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult _async_finish_geography(self, dict[str, str] user_input, str integration_type)
ConfigFlowResult async_step_reauth_confirm(self, dict[str, str]|None user_input=None)
ConfigFlowResult async_step_geography_by_name(self, dict[str, str]|None user_input=None)
vol.Schema geography_coords_schema(self)
ConfigFlowResult async_step_geography_by_coords(self, dict[str, str]|None user_input=None)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult _async_init_geography(self, dict[str, str] user_input, str integration_type)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry _get_reauth_entry(self)
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_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)
_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)
str async_get_geography_id(Mapping[str, Any] geography_dict)