Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for the D-Link Power Plug integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 from pyW215.pyW215 import SmartPlug
9 import voluptuous as vol
10 
11 from homeassistant.components import dhcp
12 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
13 from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
14 
15 from .const import CONF_USE_LEGACY_PROTOCOL, DEFAULT_NAME, DEFAULT_USERNAME, DOMAIN
16 
17 _LOGGER = logging.getLogger(__name__)
18 
19 
20 class DLinkFlowHandler(ConfigFlow, domain=DOMAIN):
21  """Handle a config flow for D-Link Power Plug."""
22 
23  def __init__(self) -> None:
24  """Initialize a D-Link Power Plug flow."""
25  self.ip_addressip_address: str | None = None
26 
27  async def async_step_dhcp(
28  self, discovery_info: dhcp.DhcpServiceInfo
29  ) -> ConfigFlowResult:
30  """Handle dhcp discovery."""
31  await self.async_set_unique_idasync_set_unique_id(discovery_info.macaddress)
32  self._abort_if_unique_id_configured_abort_if_unique_id_configured(updates={CONF_HOST: discovery_info.ip})
33  for entry in self.hass.config_entries.async_entries(DOMAIN):
34  if not entry.unique_id and entry.data[CONF_HOST] == discovery_info.ip:
35  # Add mac address as the unique id, can be removed with import
36  self.hass.config_entries.async_update_entry(
37  entry, unique_id=discovery_info.macaddress
38  )
39  return self.async_abortasync_abortasync_abort(reason="already_configured")
40 
41  self.ip_addressip_address = discovery_info.ip
42  return await self.async_step_confirm_discoveryasync_step_confirm_discovery()
43 
45  self, user_input: dict[str, Any] | None = None
46  ) -> ConfigFlowResult:
47  """Allow the user to confirm adding the device."""
48  errors = {}
49  if user_input is not None:
50  if (
51  error := await self.hass.async_add_executor_job(
52  self._try_connect_try_connect, user_input
53  )
54  ) is None:
55  return self.async_create_entryasync_create_entryasync_create_entry(
56  title=DEFAULT_NAME,
57  data=user_input | {CONF_HOST: self.ip_addressip_address},
58  )
59  errors["base"] = error
60 
61  user_input = user_input or {}
62  return self.async_show_formasync_show_formasync_show_form(
63  step_id="confirm_discovery",
64  data_schema=vol.Schema(
65  {
66  vol.Optional(
67  CONF_USERNAME,
68  default=user_input.get(CONF_USERNAME, DEFAULT_USERNAME),
69  ): str,
70  vol.Required(CONF_PASSWORD): str,
71  vol.Required(CONF_USE_LEGACY_PROTOCOL): bool,
72  }
73  ),
74  errors=errors,
75  )
76 
77  async def async_step_user(
78  self, user_input: dict[str, Any] | None = None
79  ) -> ConfigFlowResult:
80  """Handle a flow initiated by the user."""
81  errors = {}
82  if user_input is not None:
83  self._async_abort_entries_match_async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]})
84 
85  if (
86  error := await self.hass.async_add_executor_job(
87  self._try_connect_try_connect, user_input
88  )
89  ) is None:
90  return self.async_create_entryasync_create_entryasync_create_entry(
91  title=DEFAULT_NAME,
92  data=user_input,
93  )
94  errors["base"] = error
95 
96  user_input = user_input or {}
97  return self.async_show_formasync_show_formasync_show_form(
98  step_id="user",
99  data_schema=vol.Schema(
100  {
101  vol.Required(
102  CONF_HOST, default=user_input.get(CONF_HOST, self.ip_addressip_address)
103  ): str,
104  vol.Optional(
105  CONF_USERNAME,
106  default=user_input.get(CONF_USERNAME, DEFAULT_USERNAME),
107  ): str,
108  vol.Required(CONF_PASSWORD): str,
109  vol.Required(CONF_USE_LEGACY_PROTOCOL): bool,
110  }
111  ),
112  errors=errors,
113  )
114 
115  def _try_connect(self, user_input: dict[str, Any]) -> str | None:
116  """Try connecting to D-Link Power Plug."""
117  try:
118  smartplug = SmartPlug(
119  user_input.get(CONF_HOST, self.ip_addressip_address),
120  user_input[CONF_PASSWORD],
121  user_input[CONF_USERNAME],
122  user_input[CONF_USE_LEGACY_PROTOCOL],
123  )
124  except Exception:
125  _LOGGER.exception("Unexpected exception")
126  return "unknown"
127  if not smartplug.authenticated and smartplug.use_legacy_protocol:
128  return "cannot_connect"
129  return None
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_abort(self, *str reason, Mapping[str, str]|None description_placeholders=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)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)