1 """Config flow for IntelliFire integration."""
3 from __future__
import annotations
5 from collections.abc
import Mapping
6 from dataclasses
import dataclass
9 from aiohttp
import ClientConnectionError
10 from intellifire4py.cloud_interface
import IntelliFireCloudInterface
11 from intellifire4py.exceptions
import LoginError
12 from intellifire4py.local_api
import IntelliFireAPILocal
13 from intellifire4py.model
import IntelliFireCommonFireplaceData
14 import voluptuous
as vol
38 STEP_USER_DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str})
40 MANUAL_ENTRY_STRING =
"IP Address"
45 """Host info for discovery."""
52 host: str, dhcp_mode: bool =
False
54 """Validate the user input allows us to connect.
56 Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
58 LOGGER.debug(
"Instantiating IntellifireAPI with host: [%s]", host)
59 api = IntelliFireAPILocal(fireplace_ip=host)
60 await api.poll(suppress_warnings=dhcp_mode)
61 serial = api.data.serial
63 LOGGER.debug(
"Found a fireplace: %s", serial)
70 """Handle a config flow for IntelliFire."""
76 """Initialize the Config Flow Handler."""
80 self._discovered_host: DiscoveredHostInfo
83 self._not_configured_hosts: list[DiscoveredHostInfo] = []
84 self._reauth_needed: DiscoveredHostInfo
92 self, user_input: dict[str, Any] |
None =
None
93 ) -> ConfigFlowResult:
94 """Start the user flow."""
98 entry.data[CONF_SERIAL]
for entry
in current_entries
104 self, user_input: dict[str, Any] |
None =
None
105 ) -> ConfigFlowResult:
106 """Authenticate against IFTAPI Cloud in order to see configured devices.
108 Local control of IntelliFire devices requires that the user download the correct API KEY which is only available on the cloud. Cloud control of the devices requires the user has at least once authenticated against the cloud and a set of cookie variables have been stored locally.
111 errors: dict[str, str] = {}
112 LOGGER.debug(
"STEP: cloud_api")
114 if user_input
is not None:
117 await cloud_interface.login_with_credentials(
118 username=user_input[CONF_USERNAME],
119 password=user_input[CONF_PASSWORD],
125 errors[
"base"] =
"api_error"
130 data_schema=vol.Schema(
132 vol.Required(CONF_USERNAME): str,
133 vol.Required(CONF_PASSWORD): str,
139 self, user_input: dict[str, Any] |
None =
None
140 ) -> ConfigFlowResult:
141 """Step to select a device from the cloud.
143 We can only get here if we have logged in. If there is only one device available it will be auto-configured,
144 else the user will be given a choice to pick a device.
146 errors: dict[str, str] = {}
148 f
"STEP: pick_cloud_device: {user_input} - DHCP_MODE[{self._dhcp_mode}"
151 if self.
_dhcp_mode_dhcp_mode
or user_input
is not None:
154 LOGGER.debug(f
"DHCP Mode detected for serial [{serial}]")
155 if user_input
is not None:
156 serial = user_input[CONF_SERIAL]
163 fireplace = self.
cloud_api_interfacecloud_api_interface.user_data.get_data_for_serial(serial)
172 available_fireplaces: list[IntelliFireCommonFireplaceData] = [
174 for fp
in user_data.fireplaces
179 if not available_fireplaces:
183 if len(available_fireplaces) == 1:
185 fireplace=available_fireplaces[0]
189 step_id=
"pick_cloud_device",
191 data_schema=vol.Schema(
193 vol.Required(CONF_SERIAL): vol.In(
194 [fp.serial
for fp
in available_fireplaces]
201 self, fireplace: IntelliFireCommonFireplaceData
202 ) -> ConfigFlowResult:
203 """Construct a config entry based on an object of IntelliFireCommonFireplaceData."""
206 CONF_IP_ADDRESS: fireplace.ip_address,
207 CONF_API_KEY: fireplace.api_key,
208 CONF_SERIAL: fireplace.serial,
209 CONF_AUTH_COOKIE: fireplace.auth_cookie,
210 CONF_WEB_CLIENT_ID: fireplace.web_client_id,
211 CONF_USER_ID: fireplace.user_id,
216 options = {CONF_READ_MODE: API_MODE_LOCAL, CONF_CONTROL_MODE: API_MODE_LOCAL}
223 title=f
"Fireplace {fireplace.serial}", data=data, options=options
227 self, entry_data: Mapping[str, Any]
228 ) -> ConfigFlowResult:
229 """Perform reauth upon an API authentication error."""
230 LOGGER.debug(
"STEP: reauth")
236 self.context[
"title_placeholders"] = placeholders
241 self, discovery_info: DhcpServiceInfo
242 ) -> ConfigFlowResult:
243 """Handle DHCP Discovery."""
247 ip_address = discovery_info.ip
248 LOGGER.debug(
"STEP: dhcp for ip_address %s", ip_address)
253 ip_address, dhcp_mode=
True
255 except (ConnectionError, ClientConnectionError):
257 "DHCP Discovery has determined %s is not an IntelliFire device",
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult _async_create_config_entry_from_common_data(self, IntelliFireCommonFireplaceData fireplace)
ConfigFlowResult async_step_dhcp(self, DhcpServiceInfo discovery_info)
ConfigFlowResult async_step_pick_cloud_device(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_cloud_api(self, dict[str, Any]|None user_input=None)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry _get_reauth_entry(self)
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)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=None)
ConfigFlowResult async_update_reload_and_abort(self, ConfigEntry entry, *str|None|UndefinedType unique_id=UNDEFINED, str|UndefinedType title=UNDEFINED, Mapping[str, Any]|UndefinedType data=UNDEFINED, Mapping[str, Any]|UndefinedType data_updates=UNDEFINED, Mapping[str, Any]|UndefinedType options=UNDEFINED, str|UndefinedType reason=UNDEFINED, bool reload_even_if_entry_is_unchanged=True)
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)
str _async_poll_local_fireplace_for_serial(str host, bool dhcp_mode=False)