1 """Config flow to configure the Bravia TV integration."""
3 from __future__
import annotations
5 from collections.abc
import Mapping
6 from typing
import Any, cast
7 from urllib.parse
import urlparse
9 from aiohttp
import CookieJar
10 from pybravia
import BraviaAuthError, BraviaClient, BraviaError, BraviaNotSupported
11 import voluptuous
as vol
32 """Handle a config flow for Bravia TV integration."""
37 """Initialize config flow."""
38 self.
clientclient: BraviaClient |
None =
None
42 """Create Bravia TV client from config."""
46 cookie_jar=CookieJar(unsafe=
True, quote_cookie=
False),
48 self.
clientclient = BraviaClient(host=host, session=session)
51 """Generate client_id and nickname."""
52 uuid = await instance_id.async_get(self.hass)
53 return uuid, f
"{NICKNAME_PREFIX} {uuid[:6]}"
56 """Connect to Bravia TV device from config."""
63 await self.
clientclient.connect(psk=pin)
67 await self.
clientclient.connect(pin=pin, clientid=client_id, nickname=nickname)
68 await self.
clientclient.set_wol_mode(
True)
71 """Create Bravia TV device from config."""
75 system_info = await self.
clientclient.get_system_info()
76 cid = system_info[ATTR_CID].lower()
77 title = system_info[ATTR_MODEL]
79 self.
device_configdevice_config[CONF_MAC] = system_info[ATTR_MAC]
87 """Reauthorize Bravia TV device from config."""
96 self, user_input: dict[str, Any] |
None =
None
97 ) -> ConfigFlowResult:
98 """Handle the initial step."""
99 errors: dict[str, str] = {}
101 if user_input
is not None:
102 host = user_input[CONF_HOST]
107 errors[CONF_HOST] =
"invalid_host"
111 data_schema=vol.Schema({vol.Required(CONF_HOST): str}),
116 self, user_input: dict[str, Any] |
None =
None
117 ) -> ConfigFlowResult:
118 """Handle authorize step."""
121 if user_input
is not None:
122 self.
device_configdevice_config[CONF_USE_PSK] = user_input[CONF_USE_PSK]
123 if user_input[CONF_USE_PSK]:
129 data_schema=vol.Schema(
131 vol.Required(CONF_USE_PSK, default=
False): bool,
137 self, user_input: dict[str, Any] |
None =
None
138 ) -> ConfigFlowResult:
139 """Handle PIN authorize step."""
140 errors: dict[str, str] = {}
143 if user_input
is not None:
144 self.
device_configdevice_config[CONF_PIN] = user_input[CONF_PIN]
151 except BraviaAuthError:
152 errors[
"base"] =
"invalid_auth"
153 except BraviaNotSupported:
154 errors[
"base"] =
"unsupported_model"
156 errors[
"base"] =
"cannot_connect"
161 await self.
clientclient.pair(client_id, nickname)
167 data_schema=vol.Schema(
169 vol.Required(CONF_PIN): str,
176 self, user_input: dict[str, Any] |
None =
None
177 ) -> ConfigFlowResult:
178 """Handle PSK authorize step."""
179 errors: dict[str, str] = {}
181 if user_input
is not None:
182 self.
device_configdevice_config[CONF_PIN] = user_input[CONF_PIN]
187 except BraviaAuthError:
188 errors[
"base"] =
"invalid_auth"
189 except BraviaNotSupported:
190 errors[
"base"] =
"unsupported_model"
192 errors[
"base"] =
"cannot_connect"
196 data_schema=vol.Schema(
198 vol.Required(CONF_PIN): str,
205 self, discovery_info: ssdp.SsdpServiceInfo
206 ) -> ConfigFlowResult:
207 """Handle a discovered device."""
210 host = cast(str, urlparse(discovery_info.ssdp_location).hostname)
216 scalarweb_info = discovery_info.upnp[
"X_ScalarWebAPI_DeviceInfo"]
217 service_types = scalarweb_info[
"X_ScalarWebAPI_ServiceList"][
218 "X_ScalarWebAPI_ServiceType"
221 if "videoScreen" not in service_types:
224 model_name = discovery_info.upnp[ssdp.ATTR_UPNP_MODEL_NAME]
225 friendly_name = discovery_info.upnp[ssdp.ATTR_UPNP_FRIENDLY_NAME]
227 self.context[
"title_placeholders"] = {
228 CONF_NAME: f
"{model_name} ({friendly_name})",
236 self, user_input: dict[str, Any] |
None =
None
237 ) -> ConfigFlowResult:
238 """Allow the user to confirm adding the device."""
239 if user_input
is not None:
245 self, entry_data: Mapping[str, Any]
246 ) -> ConfigFlowResult:
247 """Handle configuration by re-auth."""
ConfigFlowResult async_reauth_device(self)
ConfigFlowResult async_step_ssdp(self, ssdp.SsdpServiceInfo discovery_info)
ConfigFlowResult async_step_psk(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_create_device(self)
None async_connect_device(self)
ConfigFlowResult async_step_confirm(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_pin(self, dict[str, Any]|None user_input=None)
tuple[str, str] gen_instance_ids(self)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult async_step_authorize(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)
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)
aiohttp.ClientSession async_create_clientsession()
bool is_host_valid(str host)