Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for bluesound."""
2 
3 import logging
4 from typing import Any
5 
6 from pyblu import Player, SyncStatus
7 from pyblu.errors import PlayerUnreachableError
8 import voluptuous as vol
9 
10 from homeassistant.components import zeroconf
11 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
12 from homeassistant.const import CONF_HOST, CONF_PORT
13 from homeassistant.helpers.aiohttp_client import async_get_clientsession
14 
15 from .const import DOMAIN
16 from .media_player import DEFAULT_PORT
17 from .utils import format_unique_id
18 
19 _LOGGER = logging.getLogger(__name__)
20 
21 
22 class BluesoundConfigFlow(ConfigFlow, domain=DOMAIN):
23  """Bluesound config flow."""
24 
25  VERSION = 1
26  MINOR_VERSION = 1
27 
28  def __init__(self) -> None:
29  """Initialize the config flow."""
30  self._host_host: str | None = None
31  self._port_port = DEFAULT_PORT
32  self._sync_status_sync_status: SyncStatus | None = None
33 
34  async def async_step_user(
35  self, user_input: dict[str, Any] | None = None
36  ) -> ConfigFlowResult:
37  """Handle a flow initiated by the user."""
38  errors: dict[str, str] = {}
39  if user_input is not None:
40  session = async_get_clientsession(self.hass)
41  async with Player(
42  user_input[CONF_HOST], user_input[CONF_PORT], session=session
43  ) as player:
44  try:
45  sync_status = await player.sync_status(timeout=1)
46  except PlayerUnreachableError:
47  errors["base"] = "cannot_connect"
48  else:
49  await self.async_set_unique_idasync_set_unique_id(
50  format_unique_id(sync_status.mac, user_input[CONF_PORT])
51  )
52  self._abort_if_unique_id_configured_abort_if_unique_id_configured(
53  updates={
54  CONF_HOST: user_input[CONF_HOST],
55  }
56  )
57 
58  return self.async_create_entryasync_create_entryasync_create_entry(
59  title=sync_status.name,
60  data=user_input,
61  )
62 
63  return self.async_show_formasync_show_formasync_show_form(
64  step_id="user",
65  errors=errors,
66  data_schema=vol.Schema(
67  {
68  vol.Required(CONF_HOST): str,
69  vol.Optional(CONF_PORT, default=11000): int,
70  }
71  ),
72  )
73 
74  async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
75  """Import bluesound config entry from configuration.yaml."""
76  session = async_get_clientsession(self.hass)
77  async with Player(
78  import_data[CONF_HOST], import_data[CONF_PORT], session=session
79  ) as player:
80  try:
81  sync_status = await player.sync_status(timeout=1)
82  except PlayerUnreachableError:
83  return self.async_abortasync_abortasync_abort(reason="cannot_connect")
84 
85  await self.async_set_unique_idasync_set_unique_id(
86  format_unique_id(sync_status.mac, import_data[CONF_PORT])
87  )
88  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
89 
90  return self.async_create_entryasync_create_entryasync_create_entry(
91  title=sync_status.name,
92  data=import_data,
93  )
94 
96  self, discovery_info: zeroconf.ZeroconfServiceInfo
97  ) -> ConfigFlowResult:
98  """Handle a flow initialized by zeroconf discovery."""
99  if discovery_info.port is not None:
100  self._port_port = discovery_info.port
101 
102  session = async_get_clientsession(self.hass)
103  try:
104  async with Player(
105  discovery_info.host, self._port_port, session=session
106  ) as player:
107  sync_status = await player.sync_status(timeout=1)
108  except PlayerUnreachableError:
109  return self.async_abortasync_abortasync_abort(reason="cannot_connect")
110 
111  await self.async_set_unique_idasync_set_unique_id(format_unique_id(sync_status.mac, self._port_port))
112 
113  self._host_host = discovery_info.host
114  self._sync_status_sync_status = sync_status
115 
116  self._abort_if_unique_id_configured_abort_if_unique_id_configured(
117  updates={
118  CONF_HOST: self._host_host,
119  }
120  )
121 
122  self.context.update(
123  {
124  "title_placeholders": {"name": sync_status.name},
125  "configuration_url": f"http://{discovery_info.host}",
126  }
127  )
128  return await self.async_step_confirmasync_step_confirm()
129 
131  self, user_input: dict[str, Any] | None = None
132  ) -> ConfigFlowResult:
133  """Confirm the zeroconf setup."""
134  assert self._sync_status_sync_status is not None
135  assert self._host_host is not None
136 
137  if user_input is not None:
138  return self.async_create_entryasync_create_entryasync_create_entry(
139  title=self._sync_status_sync_status.name,
140  data={
141  CONF_HOST: self._host_host,
142  CONF_PORT: self._port_port,
143  },
144  )
145 
146  return self.async_show_formasync_show_formasync_show_form(
147  step_id="confirm",
148  description_placeholders={
149  "name": self._sync_status_sync_status.name,
150  "host": self._host_host,
151  },
152  )
ConfigFlowResult async_step_confirm(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:132
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:36
ConfigFlowResult async_step_import(self, dict[str, Any] import_data)
Definition: config_flow.py:74
ConfigFlowResult async_step_zeroconf(self, zeroconf.ZeroconfServiceInfo discovery_info)
Definition: config_flow.py:97
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_abort(self, *str reason, Mapping[str, str]|None description_placeholders=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)
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)