Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for Cast."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 import voluptuous as vol
8 
9 from homeassistant.components import onboarding, zeroconf
10 from homeassistant.config_entries import (
11  ConfigEntry,
12  ConfigFlow,
13  ConfigFlowResult,
14  OptionsFlow,
15 )
16 from homeassistant.const import CONF_UUID
17 from homeassistant.core import callback
18 from homeassistant.helpers import config_validation as cv
19 
20 from .const import CONF_IGNORE_CEC, CONF_KNOWN_HOSTS, DOMAIN
21 
22 IGNORE_CEC_SCHEMA = vol.Schema(vol.All(cv.ensure_list, [cv.string]))
23 KNOWN_HOSTS_SCHEMA = vol.Schema(vol.All(cv.ensure_list, [cv.string]))
24 WANTED_UUID_SCHEMA = vol.Schema(vol.All(cv.ensure_list, [cv.string]))
25 
26 
27 class FlowHandler(ConfigFlow, domain=DOMAIN):
28  """Handle a config flow."""
29 
30  VERSION = 1
31 
32  def __init__(self) -> None:
33  """Initialize flow."""
34  self._ignore_cec_ignore_cec = set[str]()
35  self._known_hosts_known_hosts = set[str]()
36  self._wanted_uuid_wanted_uuid = set[str]()
37 
38  @staticmethod
39  @callback
41  config_entry: ConfigEntry,
42  ) -> CastOptionsFlowHandler:
43  """Get the options flow for this handler."""
44  return CastOptionsFlowHandler()
45 
46  async def async_step_user(
47  self, user_input: dict[str, Any] | None = None
48  ) -> ConfigFlowResult:
49  """Handle a flow initialized by the user."""
50  return await self.async_step_configasync_step_config()
51 
53  self, discovery_info: zeroconf.ZeroconfServiceInfo
54  ) -> ConfigFlowResult:
55  """Handle a flow initialized by zeroconf discovery."""
56  await self.async_set_unique_idasync_set_unique_id(DOMAIN)
57 
58  return await self.async_step_confirmasync_step_confirm()
59 
60  async def async_step_config(
61  self, user_input: dict[str, Any] | None = None
62  ) -> ConfigFlowResult:
63  """Confirm the setup."""
64  errors = {}
65  data = {CONF_KNOWN_HOSTS: self._known_hosts_known_hosts}
66 
67  if user_input is not None:
68  bad_hosts = False
69  known_hosts = user_input[CONF_KNOWN_HOSTS]
70  known_hosts = [x.strip() for x in known_hosts.split(",") if x.strip()]
71  try:
72  known_hosts = KNOWN_HOSTS_SCHEMA(known_hosts)
73  except vol.Invalid:
74  errors["base"] = "invalid_known_hosts"
75  bad_hosts = True
76  else:
77  self._known_hosts_known_hosts = known_hosts
78  data = self._get_data_get_data()
79  if not bad_hosts:
80  return self.async_create_entryasync_create_entryasync_create_entry(title="Google Cast", data=data)
81 
82  fields = {}
83  fields[vol.Optional(CONF_KNOWN_HOSTS, default="")] = str
84 
85  return self.async_show_formasync_show_formasync_show_form(
86  step_id="config", data_schema=vol.Schema(fields), errors=errors
87  )
88 
89  async def async_step_confirm(
90  self, user_input: dict[str, Any] | None = None
91  ) -> ConfigFlowResult:
92  """Confirm the setup."""
93 
94  data = self._get_data_get_data()
95 
96  if user_input is not None or not onboarding.async_is_onboarded(self.hass):
97  return self.async_create_entryasync_create_entryasync_create_entry(title="Google Cast", data=data)
98 
99  return self.async_show_formasync_show_formasync_show_form(step_id="confirm")
100 
101  def _get_data(self):
102  return {
103  CONF_IGNORE_CEC: list(self._ignore_cec_ignore_cec),
104  CONF_KNOWN_HOSTS: list(self._known_hosts_known_hosts),
105  CONF_UUID: list(self._wanted_uuid_wanted_uuid),
106  }
107 
108 
110  """Handle Google Cast options."""
111 
112  def __init__(self) -> None:
113  """Initialize Google Cast options flow."""
114  self.updated_configupdated_config: dict[str, Any] = {}
115 
116  async def async_step_init(self, user_input: None = None) -> ConfigFlowResult:
117  """Manage the Google Cast options."""
118  return await self.async_step_basic_optionsasync_step_basic_options()
119 
121  self, user_input: dict[str, Any] | None = None
122  ) -> ConfigFlowResult:
123  """Manage the Google Cast options."""
124  errors: dict[str, str] = {}
125  current_config = self.config_entryconfig_entryconfig_entry.data
126  if user_input is not None:
127  bad_hosts, known_hosts = _string_to_list(
128  user_input.get(CONF_KNOWN_HOSTS, ""), KNOWN_HOSTS_SCHEMA
129  )
130 
131  if not bad_hosts:
132  self.updated_configupdated_config = dict(current_config)
133  self.updated_configupdated_config[CONF_KNOWN_HOSTS] = known_hosts
134 
135  if self.show_advanced_optionsshow_advanced_options:
136  return await self.async_step_advanced_optionsasync_step_advanced_options()
137 
138  self.hass.config_entries.async_update_entry(
139  self.config_entryconfig_entryconfig_entry, data=self.updated_configupdated_config
140  )
141  return self.async_create_entryasync_create_entry(title="", data={})
142 
143  fields: dict[vol.Marker, type[str]] = {}
144  suggested_value = _list_to_string(current_config.get(CONF_KNOWN_HOSTS))
145  _add_with_suggestion(fields, CONF_KNOWN_HOSTS, suggested_value)
146 
147  return self.async_show_formasync_show_form(
148  step_id="basic_options",
149  data_schema=vol.Schema(fields),
150  errors=errors,
151  last_step=not self.show_advanced_optionsshow_advanced_options,
152  )
153 
155  self, user_input: dict[str, Any] | None = None
156  ) -> ConfigFlowResult:
157  """Manage the Google Cast options."""
158  errors: dict[str, str] = {}
159  if user_input is not None:
160  bad_cec, ignore_cec = _string_to_list(
161  user_input.get(CONF_IGNORE_CEC, ""), IGNORE_CEC_SCHEMA
162  )
163  bad_uuid, wanted_uuid = _string_to_list(
164  user_input.get(CONF_UUID, ""), WANTED_UUID_SCHEMA
165  )
166 
167  if not bad_cec and not bad_uuid:
168  self.updated_configupdated_config[CONF_IGNORE_CEC] = ignore_cec
169  self.updated_configupdated_config[CONF_UUID] = wanted_uuid
170  self.hass.config_entries.async_update_entry(
171  self.config_entryconfig_entryconfig_entry, data=self.updated_configupdated_config
172  )
173  return self.async_create_entryasync_create_entry(title="", data={})
174 
175  fields: dict[vol.Marker, type[str]] = {}
176  current_config = self.config_entryconfig_entryconfig_entry.data
177  suggested_value = _list_to_string(current_config.get(CONF_UUID))
178  _add_with_suggestion(fields, CONF_UUID, suggested_value)
179  suggested_value = _list_to_string(current_config.get(CONF_IGNORE_CEC))
180  _add_with_suggestion(fields, CONF_IGNORE_CEC, suggested_value)
181 
182  return self.async_show_formasync_show_form(
183  step_id="advanced_options",
184  data_schema=vol.Schema(fields),
185  errors=errors,
186  last_step=True,
187  )
188 
189 
190 def _list_to_string(items):
191  comma_separated_string = ""
192  if items:
193  comma_separated_string = ",".join(items)
194  return comma_separated_string
195 
196 
197 def _string_to_list(string, schema):
198  invalid = False
199  items = [x.strip() for x in string.split(",") if x.strip()]
200  try:
201  items = schema(items)
202  except vol.Invalid:
203  invalid = True
204 
205  return invalid, items
206 
207 
209  fields: dict[vol.Marker, type[str]], key: str, suggested_value: str
210 ) -> None:
211  fields[vol.Optional(key, description={"suggested_value": suggested_value})] = str
ConfigFlowResult async_step_advanced_options(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:156
ConfigFlowResult async_step_basic_options(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:122
ConfigFlowResult async_step_init(self, None user_input=None)
Definition: config_flow.py:116
ConfigFlowResult async_step_zeroconf(self, zeroconf.ZeroconfServiceInfo discovery_info)
Definition: config_flow.py:54
CastOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
Definition: config_flow.py:42
ConfigFlowResult async_step_config(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:62
ConfigFlowResult async_step_confirm(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:91
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:48
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)
None config_entry(self, ConfigEntry value)
bool show_advanced_options(self)
_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)
None _add_with_suggestion(dict[vol.Marker, type[str]] fields, str key, str suggested_value)
Definition: config_flow.py:210