Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Rachio integration."""
2 
3 from __future__ import annotations
4 
5 from http import HTTPStatus
6 import logging
7 from typing import Any
8 
9 from rachiopy import Rachio
10 from requests.exceptions import ConnectTimeout
11 import voluptuous as vol
12 
13 from homeassistant.components import zeroconf
14 from homeassistant.config_entries import (
15  ConfigEntry,
16  ConfigFlow,
17  ConfigFlowResult,
18  OptionsFlow,
19 )
20 from homeassistant.const import CONF_API_KEY
21 from homeassistant.core import HomeAssistant, callback
22 from homeassistant.exceptions import HomeAssistantError
23 
24 from .const import (
25  CONF_MANUAL_RUN_MINS,
26  DEFAULT_MANUAL_RUN_MINS,
27  DOMAIN,
28  KEY_ID,
29  KEY_STATUS,
30  KEY_USERNAME,
31 )
32 
33 _LOGGER = logging.getLogger(__name__)
34 
35 DATA_SCHEMA = vol.Schema({vol.Required(CONF_API_KEY): str}, extra=vol.ALLOW_EXTRA)
36 
37 
38 async def validate_input(hass: HomeAssistant, data):
39  """Validate the user input allows us to connect.
40 
41  Data has the keys from DATA_SCHEMA with values provided by the user.
42  """
43  rachio = Rachio(data[CONF_API_KEY])
44  username = None
45  try:
46  data = await hass.async_add_executor_job(rachio.person.info)
47  _LOGGER.debug("rachio.person.getInfo: %s", data)
48  if int(data[0][KEY_STATUS]) != HTTPStatus.OK:
49  raise InvalidAuth
50 
51  rachio_id = data[1][KEY_ID]
52  data = await hass.async_add_executor_job(rachio.person.get, rachio_id)
53  _LOGGER.debug("rachio.person.get: %s", data)
54  if int(data[0][KEY_STATUS]) != HTTPStatus.OK:
55  raise CannotConnect
56 
57  username = data[1][KEY_USERNAME]
58  except ConnectTimeout as error:
59  _LOGGER.error("Could not reach the Rachio API: %s", error)
60  raise CannotConnect from error
61 
62  # Return info that you want to store in the config entry.
63  return {"title": username}
64 
65 
66 class RachioConfigFlow(ConfigFlow, domain=DOMAIN):
67  """Handle a config flow for Rachio."""
68 
69  VERSION = 1
70 
71  async def async_step_user(
72  self, user_input: dict[str, Any] | None = None
73  ) -> ConfigFlowResult:
74  """Handle the initial step."""
75  errors = {}
76  if user_input is not None:
77  await self.async_set_unique_idasync_set_unique_id(user_input[CONF_API_KEY])
78  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
79  try:
80  info = await validate_input(self.hass, user_input)
81  return self.async_create_entryasync_create_entryasync_create_entry(title=info["title"], data=user_input)
82  except CannotConnect:
83  errors["base"] = "cannot_connect"
84  except InvalidAuth:
85  errors["base"] = "invalid_auth"
86  except Exception:
87  _LOGGER.exception("Unexpected exception")
88  errors["base"] = "unknown"
89 
90  return self.async_show_formasync_show_formasync_show_form(
91  step_id="user", data_schema=DATA_SCHEMA, errors=errors
92  )
93 
94  async def async_step_homekit(
95  self, discovery_info: zeroconf.ZeroconfServiceInfo
96  ) -> ConfigFlowResult:
97  """Handle HomeKit discovery."""
98  self._async_abort_entries_match_async_abort_entries_match()
99  await self.async_set_unique_idasync_set_unique_id(
100  discovery_info.properties[zeroconf.ATTR_PROPERTIES_ID]
101  )
102  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
103  return await self.async_step_userasync_step_userasync_step_user()
104 
105  @staticmethod
106  @callback
108  config_entry: ConfigEntry,
109  ) -> OptionsFlowHandler:
110  """Get the options flow for this handler."""
111  return OptionsFlowHandler()
112 
113 
115  """Handle a option flow for Rachio."""
116 
117  async def async_step_init(
118  self, user_input: dict[str, int] | None = None
119  ) -> ConfigFlowResult:
120  """Handle options flow."""
121  if user_input is not None:
122  return self.async_create_entryasync_create_entry(title="", data=user_input)
123 
124  data_schema = vol.Schema(
125  {
126  vol.Optional(
127  CONF_MANUAL_RUN_MINS,
128  default=self.config_entryconfig_entryconfig_entry.options.get(
129  CONF_MANUAL_RUN_MINS, DEFAULT_MANUAL_RUN_MINS
130  ),
131  ): int
132  }
133  )
134  return self.async_show_formasync_show_form(step_id="init", data_schema=data_schema)
135 
136 
138  """Error to indicate we cannot connect."""
139 
140 
141 class InvalidAuth(HomeAssistantError):
142  """Error to indicate there is invalid auth."""
ConfigFlowResult async_step_init(self, dict[str, int]|None user_input=None)
Definition: config_flow.py:119
ConfigFlowResult async_step_homekit(self, zeroconf.ZeroconfServiceInfo discovery_info)
Definition: config_flow.py:96
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:73
OptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
Definition: config_flow.py:109
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_step_user(self, dict[str, Any]|None user_input=None)
None _async_abort_entries_match(self, dict[str, Any]|None match_dict=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)
None config_entry(self, ConfigEntry value)
_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)
def validate_input(HomeAssistant hass, data)
Definition: config_flow.py:38