Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Test config flow for Insteon."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 from pyinsteon import async_connect
9 
10 from homeassistant.components import dhcp, usb
11 from homeassistant.config_entries import (
12  DEFAULT_DISCOVERY_UNIQUE_ID,
13  ConfigFlow,
14  ConfigFlowResult,
15 )
16 from homeassistant.const import CONF_DEVICE, CONF_HOST, CONF_NAME
17 from homeassistant.helpers.device_registry import format_mac
18 
19 from .const import CONF_HUB_VERSION, DOMAIN
20 from .schemas import build_hub_schema, build_plm_manual_schema, build_plm_schema
21 from .utils import async_get_usb_ports
22 
23 STEP_PLM = "plm"
24 STEP_PLM_MANUALLY = "plm_manually"
25 STEP_HUB_V1 = "hubv1"
26 STEP_HUB_V2 = "hubv2"
27 STEP_CHANGE_HUB_CONFIG = "change_hub_config"
28 STEP_CHANGE_PLM_CONFIG = "change_plm_config"
29 STEP_ADD_X10 = "add_x10"
30 STEP_ADD_OVERRIDE = "add_override"
31 STEP_REMOVE_OVERRIDE = "remove_override"
32 STEP_REMOVE_X10 = "remove_x10"
33 MODEM_TYPE = "modem_type"
34 PLM_MANUAL = "manual"
35 
36 _LOGGER = logging.getLogger(__name__)
37 
38 
39 async def _async_connect(**kwargs):
40  """Connect to the Insteon modem."""
41  try:
42  await async_connect(**kwargs)
43  except ConnectionError:
44  _LOGGER.error("Could not connect to Insteon modem")
45  return False
46 
47  _LOGGER.debug("Connected to Insteon modem")
48  return True
49 
50 
51 class InsteonFlowHandler(ConfigFlow, domain=DOMAIN):
52  """Insteon config flow handler."""
53 
54  _device_path: str
55  _device_name: str
56  discovered_conf: dict[str, str] = {}
57 
58  async def async_step_user(
59  self, user_input: dict[str, Any] | None = None
60  ) -> ConfigFlowResult:
61  """Init the config flow."""
62  modem_types = [STEP_PLM, STEP_HUB_V1, STEP_HUB_V2]
63  return self.async_show_menuasync_show_menu(step_id="user", menu_options=modem_types)
64 
65  async def async_step_plm(
66  self, user_input: dict[str, Any] | None = None
67  ) -> ConfigFlowResult:
68  """Set up the PLM modem type."""
69  errors = {}
70  if user_input is not None:
71  if user_input[CONF_DEVICE] == PLM_MANUAL:
72  return await self.async_step_plm_manually()
73  if await _async_connect(**user_input):
74  return self.async_create_entryasync_create_entryasync_create_entry(title="", data=user_input)
75  errors["base"] = "cannot_connect"
76  schema_defaults = user_input if user_input is not None else {}
77  ports = await async_get_usb_ports(self.hass)
78  if not ports:
79  return await self.async_step_plm_manually()
80  ports[PLM_MANUAL] = "Enter manually"
81  data_schema = build_plm_schema(ports, **schema_defaults)
82  return self.async_show_formasync_show_formasync_show_form(
83  step_id=STEP_PLM, data_schema=data_schema, errors=errors
84  )
85 
86  async def async_step_plm_manually(
87  self, user_input: dict[str, Any] | None = None
88  ) -> ConfigFlowResult:
89  """Set up the PLM modem type manually."""
90  errors = {}
91  schema_defaults = {}
92  if user_input is not None:
93  if await _async_connect(**user_input):
94  return self.async_create_entryasync_create_entryasync_create_entry(title="", data=user_input)
95  errors["base"] = "cannot_connect"
96  schema_defaults = user_input
97  data_schema = build_plm_manual_schema(**schema_defaults)
98  return self.async_show_formasync_show_formasync_show_form(
99  step_id=STEP_PLM_MANUALLY, data_schema=data_schema, errors=errors
100  )
101 
102  async def async_step_hubv1(
103  self, user_input: dict[str, Any] | None = None
104  ) -> ConfigFlowResult:
105  """Set up the Hub v1 modem type."""
106  return await self._async_setup_hub(hub_version=1, user_input=user_input)
107 
108  async def async_step_hubv2(
109  self, user_input: dict[str, Any] | None = None
110  ) -> ConfigFlowResult:
111  """Set up the Hub v2 modem type."""
112  return await self._async_setup_hub(hub_version=2, user_input=user_input)
113 
114  async def _async_setup_hub(
115  self, hub_version: int, user_input: dict[str, Any] | None
116  ) -> ConfigFlowResult:
117  """Set up the Hub versions 1 and 2."""
118  errors = {}
119  if user_input is not None:
120  user_input[CONF_HUB_VERSION] = hub_version
121  if await _async_connect(**user_input):
122  return self.async_create_entryasync_create_entryasync_create_entry(title="", data=user_input)
123  user_input.pop(CONF_HUB_VERSION)
124  errors["base"] = "cannot_connect"
125  schema_defaults = user_input if user_input is not None else self.discovered_confdiscovered_conf
126  data_schema = build_hub_schema(hub_version=hub_version, **schema_defaults)
127  step_id = STEP_HUB_V2 if hub_version == 2 else STEP_HUB_V1
128  return self.async_show_formasync_show_formasync_show_form(
129  step_id=step_id, data_schema=data_schema, errors=errors
130  )
131 
132  async def async_step_usb(
133  self, discovery_info: usb.UsbServiceInfo
134  ) -> ConfigFlowResult:
135  """Handle USB discovery."""
136  self._device_path_device_path = discovery_info.device
137  self._device_name_device_name = usb.human_readable_device_name(
138  discovery_info.device,
139  discovery_info.serial_number,
140  discovery_info.manufacturer,
141  discovery_info.description,
142  discovery_info.vid,
143  discovery_info.pid,
144  )
145  self._set_confirm_only_set_confirm_only()
146  self.context["title_placeholders"] = {
147  CONF_NAME: f"Insteon PLM {self._device_name}"
148  }
149  await self.async_set_unique_idasync_set_unique_id(DEFAULT_DISCOVERY_UNIQUE_ID)
150  return await self.async_step_confirm_usb()
151 
152  async def async_step_confirm_usb(
153  self, user_input: dict[str, Any] | None = None
154  ) -> ConfigFlowResult:
155  """Confirm a USB discovery."""
156  if user_input is not None:
157  return await self.async_step_plm({CONF_DEVICE: self._device_path_device_path})
158 
159  return self.async_show_formasync_show_formasync_show_form(
160  step_id="confirm_usb",
161  description_placeholders={CONF_NAME: self._device_name_device_name},
162  )
163 
164  async def async_step_dhcp(
165  self, discovery_info: dhcp.DhcpServiceInfo
166  ) -> ConfigFlowResult:
167  """Handle a DHCP discovery."""
168  self.discovered_confdiscovered_conf = {CONF_HOST: discovery_info.ip}
169  self.context["title_placeholders"] = {
170  CONF_NAME: f"Insteon Hub {discovery_info.ip}"
171  }
172  await self.async_set_unique_idasync_set_unique_id(format_mac(discovery_info.macaddress))
173  return await self.async_step_userasync_step_userasync_step_user()
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:60
ConfigFlowResult async_step_dhcp(self, DhcpServiceInfo discovery_info)
ConfigFlowResult async_step_usb(self, UsbServiceInfo discovery_info)
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)
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_show_menu(self, *str|None step_id=None, Container[str] menu_options, Mapping[str, str]|None description_placeholders=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 build_hub_schema(hub_version, host=vol.UNDEFINED, port=vol.UNDEFINED, username=vol.UNDEFINED, password=vol.UNDEFINED)
Definition: schemas.py:140
def build_plm_manual_schema(device=vol.UNDEFINED)
Definition: schemas.py:129
def build_plm_schema(dict[str, str] ports, device=vol.UNDEFINED)
Definition: schemas.py:122
dict[str, str] async_get_usb_ports(HomeAssistant hass)
Definition: config_flow.py:169