1 """Config flow for Control4 integration."""
3 from __future__
import annotations
6 from typing
import TYPE_CHECKING, Any
8 from aiohttp.client_exceptions
import ClientError
9 from pyControl4.account
import C4Account
10 from pyControl4.director
import C4Director
11 from pyControl4.error_handling
import NotFound, Unauthorized
12 import voluptuous
as vol
32 CONF_CONTROLLER_UNIQUE_ID,
33 DEFAULT_SCAN_INTERVAL,
38 _LOGGER = logging.getLogger(__name__)
40 DATA_SCHEMA = vol.Schema(
42 vol.Required(CONF_HOST): str,
43 vol.Required(CONF_USERNAME): str,
44 vol.Required(CONF_PASSWORD): str,
50 """Validates that config details can be used to authenticate and communicate with Control4."""
53 self, host: str, username: str, password: str, hass: HomeAssistant
64 """Test if we can authenticate with the Control4 account API."""
66 account_session = aiohttp_client.async_get_clientsession(self.
hasshass)
67 account = C4Account(self.
usernameusername, self.
passwordpassword, account_session)
69 await account.getAccountBearerToken()
72 account_controllers = await account.getAccountControllers()
79 except (Unauthorized, NotFound):
84 """Test if we can connect to the local Control4 Director."""
86 director_session = aiohttp_client.async_get_clientsession(
87 self.
hasshass, verify_ssl=
False
89 director = C4Director(
92 await director.getAllItemInfo()
93 except (Unauthorized, ClientError, TimeoutError):
94 _LOGGER.error(
"Failed to connect to the Control4 controller")
100 """Handle a config flow for Control4."""
105 self, user_input: dict[str, Any] |
None =
None
106 ) -> ConfigFlowResult:
107 """Handle the initial step."""
109 if user_input
is not None:
111 user_input[CONF_HOST],
112 user_input[CONF_USERNAME],
113 user_input[CONF_PASSWORD],
117 if not await hub.authenticate():
119 if not await hub.connect_to_director():
122 errors[
"base"] =
"invalid_auth"
123 except CannotConnect:
124 errors[
"base"] =
"cannot_connect"
126 _LOGGER.exception(
"Unexpected exception")
127 errors[
"base"] =
"unknown"
130 controller_unique_id = hub.controller_unique_id
132 assert hub.controller_unique_id
133 mac = (controller_unique_id.split(
"_", 3))[2]
138 title=controller_unique_id,
140 CONF_HOST: user_input[CONF_HOST],
141 CONF_USERNAME: user_input[CONF_USERNAME],
142 CONF_PASSWORD: user_input[CONF_PASSWORD],
143 CONF_CONTROLLER_UNIQUE_ID: controller_unique_id,
148 step_id=
"user", data_schema=DATA_SCHEMA, errors=errors
154 config_entry: ConfigEntry,
155 ) -> OptionsFlowHandler:
156 """Get the options flow for this handler."""
161 """Handle a option flow for Control4."""
164 self, user_input: dict[str, Any] |
None =
None
165 ) -> ConfigFlowResult:
166 """Handle options flow."""
167 if user_input
is not None:
170 data_schema = vol.Schema(
175 CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
177 ): vol.All(cv.positive_int, vol.Clamp(min=MIN_SCAN_INTERVAL)),
180 return self.
async_show_formasync_show_form(step_id=
"init", data_schema=data_schema)
184 """Error to indicate we cannot connect."""
187 class InvalidAuth(HomeAssistantError):
188 """Error to indicate there is invalid auth."""
OptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
bool connect_to_director(self)
None __init__(self, str host, str username, str password, HomeAssistant hass)
ConfigFlowResult async_step_init(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|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_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)
ConfigEntry config_entry(self)
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)