Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Gogogate2."""
2 
3 from __future__ import annotations
4 
5 import dataclasses
6 import re
7 from typing import Any, Self
8 
9 from ismartgate.common import AbstractInfoResponse, ApiError
10 from ismartgate.const import GogoGate2ApiErrorCode, ISmartGateApiErrorCode
11 import voluptuous as vol
12 
13 from homeassistant.components import dhcp, zeroconf
14 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
15 from homeassistant.const import (
16  CONF_DEVICE,
17  CONF_IP_ADDRESS,
18  CONF_PASSWORD,
19  CONF_USERNAME,
20 )
21 from homeassistant.data_entry_flow import AbortFlow
22 
23 from .common import get_api
24 from .const import DEVICE_TYPE_GOGOGATE2, DEVICE_TYPE_ISMARTGATE, DOMAIN
25 
26 DEVICE_NAMES = {
27  DEVICE_TYPE_GOGOGATE2: "Gogogate2",
28  DEVICE_TYPE_ISMARTGATE: "ismartgate",
29 }
30 
31 
32 class Gogogate2FlowHandler(ConfigFlow, domain=DOMAIN):
33  """Gogogate2 config flow."""
34 
35  VERSION = 1
36 
37  def __init__(self) -> None:
38  """Initialize the config flow."""
39  self._ip_address_ip_address: str | None = None
40  self._device_type_device_type: str | None = None
41 
42  async def async_step_homekit(
43  self, discovery_info: zeroconf.ZeroconfServiceInfo
44  ) -> ConfigFlowResult:
45  """Handle homekit discovery."""
46  await self.async_set_unique_idasync_set_unique_id(
47  discovery_info.properties[zeroconf.ATTR_PROPERTIES_ID]
48  )
49  return await self._async_discovery_handler_async_discovery_handler(discovery_info.host)
50 
51  async def async_step_dhcp(
52  self, discovery_info: dhcp.DhcpServiceInfo
53  ) -> ConfigFlowResult:
54  """Handle dhcp discovery."""
55  await self.async_set_unique_idasync_set_unique_id(discovery_info.macaddress)
56  return await self._async_discovery_handler_async_discovery_handler(discovery_info.ip)
57 
58  async def _async_discovery_handler(self, ip_address: str) -> ConfigFlowResult:
59  """Start the user flow from any discovery."""
60  self._abort_if_unique_id_configured_abort_if_unique_id_configured({CONF_IP_ADDRESS: ip_address})
61 
62  self._async_abort_entries_match_async_abort_entries_match({CONF_IP_ADDRESS: ip_address})
63 
64  self._ip_address_ip_address = ip_address
65  if self.hass.config_entries.flow.async_has_matching_flow(self):
66  raise AbortFlow("already_in_progress")
67 
68  self._device_type_device_type = DEVICE_TYPE_ISMARTGATE
69  return await self.async_step_userasync_step_userasync_step_user()
70 
71  def is_matching(self, other_flow: Self) -> bool:
72  """Return True if other_flow is matching this flow."""
73  return other_flow._ip_address == self._ip_address_ip_address # noqa: SLF001
74 
75  async def async_step_user(
76  self, user_input: dict[str, Any] | None = None
77  ) -> ConfigFlowResult:
78  """Handle user initiated flow."""
79  user_input = user_input or {}
80  errors = {}
81 
82  if user_input:
83  api = get_api(self.hass, user_input)
84  try:
85  data: AbstractInfoResponse = await api.async_info()
86  data_dict = dataclasses.asdict(data)
87  title = data_dict.get(
88  "gogogatename", data_dict.get("ismartgatename", "Cover")
89  )
90  await self.async_set_unique_idasync_set_unique_id(re.sub("\\..*$", "", data.remoteaccess))
91  return self.async_create_entryasync_create_entryasync_create_entry(title=title, data=user_input)
92 
93  except ApiError as api_error:
94  device_type = user_input[CONF_DEVICE]
95  is_invalid_auth = (
96  device_type == DEVICE_TYPE_GOGOGATE2
97  and api_error.code
98  in (
99  GogoGate2ApiErrorCode.CREDENTIALS_NOT_SET,
100  GogoGate2ApiErrorCode.CREDENTIALS_INCORRECT,
101  )
102  ) or (
103  device_type == DEVICE_TYPE_ISMARTGATE
104  and api_error.code
105  in (
106  ISmartGateApiErrorCode.CREDENTIALS_NOT_SET,
107  ISmartGateApiErrorCode.CREDENTIALS_INCORRECT,
108  )
109  )
110 
111  if is_invalid_auth:
112  errors["base"] = "invalid_auth"
113  else:
114  errors["base"] = "cannot_connect"
115 
116  except Exception: # noqa: BLE001
117  errors["base"] = "cannot_connect"
118 
119  if self._ip_address_ip_address and self._device_type_device_type:
120  self.context["title_placeholders"] = {
121  CONF_DEVICE: DEVICE_NAMES[self._device_type_device_type],
122  CONF_IP_ADDRESS: self._ip_address_ip_address,
123  }
124  return self.async_show_formasync_show_formasync_show_form(
125  step_id="user",
126  data_schema=vol.Schema(
127  {
128  vol.Required(
129  CONF_DEVICE,
130  default=self._device_type_device_type
131  or user_input.get(CONF_DEVICE, DEVICE_TYPE_GOGOGATE2),
132  ): vol.In((DEVICE_TYPE_GOGOGATE2, DEVICE_TYPE_ISMARTGATE)),
133  vol.Required(
134  CONF_IP_ADDRESS,
135  default=user_input.get(CONF_IP_ADDRESS, self._ip_address_ip_address),
136  ): str,
137  vol.Required(
138  CONF_USERNAME, default=user_input.get(CONF_USERNAME, "")
139  ): str,
140  vol.Required(
141  CONF_PASSWORD, default=user_input.get(CONF_PASSWORD, "")
142  ): str,
143  }
144  ),
145  errors=errors,
146  )
ConfigFlowResult _async_discovery_handler(self, str ip_address)
Definition: config_flow.py:58
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:77
ConfigFlowResult async_step_dhcp(self, dhcp.DhcpServiceInfo discovery_info)
Definition: config_flow.py:53
ConfigFlowResult async_step_homekit(self, zeroconf.ZeroconfServiceInfo discovery_info)
Definition: config_flow.py:44
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)
_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)
Freepybox get_api(HomeAssistant hass, str host)
Definition: router.py:56