Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """OpenTherm Gateway config flow."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from typing import Any
7 
8 import pyotgw
9 from pyotgw import vars as gw_vars
10 from serial import SerialException
11 import voluptuous as vol
12 
13 from homeassistant.config_entries import (
14  ConfigEntry,
15  ConfigFlow,
16  ConfigFlowResult,
17  OptionsFlow,
18 )
19 from homeassistant.const import (
20  CONF_DEVICE,
21  CONF_ID,
22  CONF_NAME,
23  PRECISION_HALVES,
24  PRECISION_TENTHS,
25  PRECISION_WHOLE,
26 )
27 from homeassistant.core import callback
29 
30 from . import DOMAIN
31 from .const import (
32  CONF_FLOOR_TEMP,
33  CONF_READ_PRECISION,
34  CONF_SET_PRECISION,
35  CONF_TEMPORARY_OVRD_MODE,
36  CONNECTION_TIMEOUT,
37  OpenThermDataSource,
38 )
39 
40 
41 class OpenThermGwConfigFlow(ConfigFlow, domain=DOMAIN):
42  """OpenTherm Gateway Config Flow."""
43 
44  VERSION = 1
45 
46  @staticmethod
47  @callback
49  config_entry: ConfigEntry,
50  ) -> OpenThermGwOptionsFlow:
51  """Get the options flow for this handler."""
52  return OpenThermGwOptionsFlow()
53 
54  async def async_step_init(
55  self, info: dict[str, Any] | None = None
56  ) -> ConfigFlowResult:
57  """Handle config flow initiation."""
58  if info:
59  name = info[CONF_NAME]
60  device = info[CONF_DEVICE]
61  gw_id = cv.slugify(info.get(CONF_ID, name))
62 
63  entries = [e.data for e in self._async_current_entries_async_current_entries()]
64 
65  if gw_id in [e[CONF_ID] for e in entries]:
66  return self._show_form_show_form({"base": "id_exists"})
67 
68  if device in [e[CONF_DEVICE] for e in entries]:
69  return self._show_form_show_form({"base": "already_configured"})
70 
71  async def test_connection():
72  """Try to connect to the OpenTherm Gateway."""
73  otgw = pyotgw.OpenThermGateway()
74  status = await otgw.connect(device)
75  await otgw.disconnect()
76  if not status:
77  raise ConnectionError
78  return status[OpenThermDataSource.GATEWAY].get(gw_vars.OTGW_ABOUT)
79 
80  try:
81  async with asyncio.timeout(CONNECTION_TIMEOUT):
82  await test_connection()
83  except TimeoutError:
84  return self._show_form_show_form({"base": "timeout_connect"})
85  except (ConnectionError, SerialException):
86  return self._show_form_show_form({"base": "cannot_connect"})
87 
88  return self._create_entry_create_entry(gw_id, name, device)
89 
90  return self._show_form_show_form()
91 
92  async def async_step_user(
93  self, user_input: dict[str, Any] | None = None
94  ) -> ConfigFlowResult:
95  """Handle manual initiation of the config flow."""
96  return await self.async_step_initasync_step_init(user_input)
97 
98  # Deprecated import from configuration.yaml, can be removed in 2025.4.0
99  async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
100  """Import an OpenTherm Gateway device as a config entry.
101 
102  This flow is triggered by `async_setup` for configured devices.
103  """
104  formatted_config = {
105  CONF_NAME: import_data.get(CONF_NAME, import_data[CONF_ID]),
106  CONF_DEVICE: import_data[CONF_DEVICE],
107  CONF_ID: import_data[CONF_ID],
108  }
109  return await self.async_step_initasync_step_init(info=formatted_config)
110 
111  def _show_form(self, errors: dict[str, str] | None = None) -> ConfigFlowResult:
112  """Show the config flow form with possible errors."""
113  return self.async_show_formasync_show_formasync_show_form(
114  step_id="init",
115  data_schema=vol.Schema(
116  {
117  vol.Required(CONF_NAME): str,
118  vol.Required(CONF_DEVICE): str,
119  vol.Optional(CONF_ID): str,
120  }
121  ),
122  errors=errors or {},
123  )
124 
125  def _create_entry(self, gw_id, name, device):
126  """Create entry for the OpenTherm Gateway device."""
127  return self.async_create_entryasync_create_entryasync_create_entry(
128  title=name, data={CONF_ID: gw_id, CONF_DEVICE: device, CONF_NAME: name}
129  )
130 
131 
133  """Handle opentherm_gw options."""
134 
135  async def async_step_init(
136  self, user_input: dict[str, Any] | None = None
137  ) -> ConfigFlowResult:
138  """Manage the opentherm_gw options."""
139  if user_input is not None:
140  return self.async_create_entryasync_create_entry(title="", data=user_input)
141 
142  return self.async_show_formasync_show_form(
143  step_id="init",
144  data_schema=vol.Schema(
145  {
146  vol.Optional(
147  CONF_READ_PRECISION,
148  default=self.config_entryconfig_entryconfig_entry.options.get(CONF_READ_PRECISION, 0),
149  ): vol.All(
150  vol.Coerce(float),
151  vol.In(
152  [0, PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]
153  ),
154  ),
155  vol.Optional(
156  CONF_SET_PRECISION,
157  default=self.config_entryconfig_entryconfig_entry.options.get(CONF_SET_PRECISION, 0),
158  ): vol.All(
159  vol.Coerce(float),
160  vol.In(
161  [0, PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]
162  ),
163  ),
164  vol.Optional(
165  CONF_TEMPORARY_OVRD_MODE,
166  default=self.config_entryconfig_entryconfig_entry.options.get(
167  CONF_TEMPORARY_OVRD_MODE, True
168  ),
169  ): bool,
170  vol.Optional(
171  CONF_FLOOR_TEMP,
172  default=self.config_entryconfig_entryconfig_entry.options.get(CONF_FLOOR_TEMP, False),
173  ): bool,
174  }
175  ),
176  )
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:94
ConfigFlowResult async_step_init(self, dict[str, Any]|None info=None)
Definition: config_flow.py:56
OpenThermGwOptionsFlow async_get_options_flow(ConfigEntry config_entry)
Definition: config_flow.py:50
ConfigFlowResult _show_form(self, dict[str, str]|None errors=None)
Definition: config_flow.py:111
ConfigFlowResult async_step_import(self, dict[str, Any] import_data)
Definition: config_flow.py:99
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:137
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)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=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)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
str test_connection(HomeAssistant hass, str host, int port)
Definition: config_flow.py:100