From 9dd9147343acdf8b3707257de45053af1ec194e3 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Wed, 5 Oct 2022 08:24:52 +0000 Subject: [PATCH] Use HA `uuid` as `client_id` in BraviaTV (#79618) * Use uuid as clientid/nickname * Fixes after rebase * Move gen_instance_ids() to utils * Store client_id and nickname in config_entry * Update tests * Clean names * Rename consts --- homeassistant/components/braviatv/__init__.py | 9 +++---- .../components/braviatv/config_flow.py | 27 ++++++++++++++----- homeassistant/components/braviatv/const.py | 6 +++-- .../components/braviatv/coordinator.py | 22 ++++++++++----- tests/components/braviatv/test_config_flow.py | 15 +++++++++++ 5 files changed, 59 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/braviatv/__init__.py b/homeassistant/components/braviatv/__init__.py index d06482e5c71..321d864f036 100644 --- a/homeassistant/components/braviatv/__init__.py +++ b/homeassistant/components/braviatv/__init__.py @@ -7,11 +7,11 @@ from aiohttp import CookieJar from pybravia import BraviaTV from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PIN, Platform +from homeassistant.const import CONF_HOST, CONF_MAC, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers.aiohttp_client import async_create_clientsession -from .const import CONF_IGNORED_SOURCES, CONF_USE_PSK, DOMAIN +from .const import CONF_IGNORED_SOURCES, DOMAIN from .coordinator import BraviaTVCoordinator PLATFORMS: Final[list[Platform]] = [ @@ -25,8 +25,6 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b """Set up a config entry.""" host = config_entry.data[CONF_HOST] mac = config_entry.data[CONF_MAC] - pin = config_entry.data[CONF_PIN] - use_psk = config_entry.data.get(CONF_USE_PSK, False) ignored_sources = config_entry.options.get(CONF_IGNORED_SOURCES, []) session = async_create_clientsession( @@ -36,8 +34,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b coordinator = BraviaTVCoordinator( hass=hass, client=client, - pin=pin, - use_psk=use_psk, + config=config_entry.data, ignored_sources=ignored_sources, ) config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) diff --git a/homeassistant/components/braviatv/config_flow.py b/homeassistant/components/braviatv/config_flow.py index dbd08809703..f5c7826b825 100644 --- a/homeassistant/components/braviatv/config_flow.py +++ b/homeassistant/components/braviatv/config_flow.py @@ -15,6 +15,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_PIN from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult +from homeassistant.helpers import instance_id from homeassistant.helpers.aiohttp_client import async_create_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.util.network import is_host_valid @@ -24,11 +25,12 @@ from .const import ( ATTR_CID, ATTR_MAC, ATTR_MODEL, - CLIENTID_PREFIX, + CONF_CLIENT_ID, CONF_IGNORED_SOURCES, + CONF_NICKNAME, CONF_USE_PSK, DOMAIN, - NICKNAME, + NICKNAME_PREFIX, ) @@ -42,6 +44,8 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self.client: BraviaTV | None = None self.device_config: dict[str, Any] = {} self.entry: ConfigEntry | None = None + self.client_id: str = "" + self.nickname: str = "" @staticmethod @callback @@ -68,8 +72,10 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if use_psk: await self.client.connect(psk=pin) else: + self.device_config[CONF_CLIENT_ID] = self.client_id + self.device_config[CONF_NICKNAME] = self.nickname await self.client.connect( - pin=pin, clientid=CLIENTID_PREFIX, nickname=NICKNAME + pin=pin, clientid=self.client_id, nickname=self.nickname ) await self.client.set_wol_mode(True) @@ -110,6 +116,7 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Authorize Bravia TV device.""" errors: dict[str, str] = {} + self.client_id, self.nickname = await self.gen_instance_ids() if user_input is not None: self.device_config[CONF_PIN] = user_input[CONF_PIN] @@ -126,7 +133,7 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): assert self.client try: - await self.client.pair(CLIENTID_PREFIX, NICKNAME) + await self.client.pair(self.client_id, self.nickname) except BraviaTVError: return self.async_abort(reason="no_ip_control") @@ -190,6 +197,7 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Dialog that informs the user that reauth is required.""" self.create_client() + client_id, nickname = await self.gen_instance_ids() assert self.client is not None assert self.entry is not None @@ -201,8 +209,10 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if use_psk: await self.client.connect(psk=pin) else: + self.device_config[CONF_CLIENT_ID] = client_id + self.device_config[CONF_NICKNAME] = nickname await self.client.connect( - pin=pin, clientid=CLIENTID_PREFIX, nickname=NICKNAME + pin=pin, clientid=client_id, nickname=nickname ) await self.client.set_wol_mode(True) except BraviaTVError: @@ -215,7 +225,7 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_abort(reason="reauth_successful") try: - await self.client.pair(CLIENTID_PREFIX, NICKNAME) + await self.client.pair(client_id, nickname) except BraviaTVError: return self.async_abort(reason="reauth_unsuccessful") @@ -229,6 +239,11 @@ class BraviaTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ), ) + async def gen_instance_ids(self) -> tuple[str, str]: + """Generate client_id and nickname.""" + uuid = await instance_id.async_get(self.hass) + return uuid, f"{NICKNAME_PREFIX} {uuid[:6]}" + class BraviaTVOptionsFlowHandler(config_entries.OptionsFlow): """Config flow options for Bravia TV.""" diff --git a/homeassistant/components/braviatv/const.py b/homeassistant/components/braviatv/const.py index 8855499914c..e7bdf00d507 100644 --- a/homeassistant/components/braviatv/const.py +++ b/homeassistant/components/braviatv/const.py @@ -8,9 +8,11 @@ ATTR_MAC: Final = "macAddr" ATTR_MANUFACTURER: Final = "Sony" ATTR_MODEL: Final = "model" +CONF_CLIENT_ID: Final = "client_id" CONF_IGNORED_SOURCES: Final = "ignored_sources" +CONF_NICKNAME: Final = "nickname" CONF_USE_PSK: Final = "use_psk" -CLIENTID_PREFIX: Final = "HomeAssistant" DOMAIN: Final = "braviatv" -NICKNAME: Final = "Home Assistant" +LEGACY_CLIENT_ID: Final = "HomeAssistant" +NICKNAME_PREFIX: Final = "Home Assistant" diff --git a/homeassistant/components/braviatv/coordinator.py b/homeassistant/components/braviatv/coordinator.py index 46dd39bf470..1262e7bf7cc 100644 --- a/homeassistant/components/braviatv/coordinator.py +++ b/homeassistant/components/braviatv/coordinator.py @@ -5,6 +5,7 @@ from collections.abc import Awaitable, Callable, Coroutine, Iterable from datetime import timedelta from functools import wraps import logging +from types import MappingProxyType from typing import Any, Final, TypeVar from pybravia import ( @@ -19,12 +20,20 @@ from pybravia import ( from typing_extensions import Concatenate, ParamSpec from homeassistant.components.media_player import MediaType +from homeassistant.const import CONF_PIN from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.helpers.debounce import Debouncer from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import CLIENTID_PREFIX, DOMAIN, NICKNAME +from .const import ( + CONF_CLIENT_ID, + CONF_NICKNAME, + CONF_USE_PSK, + DOMAIN, + LEGACY_CLIENT_ID, + NICKNAME_PREFIX, +) _BraviaTVCoordinatorT = TypeVar("_BraviaTVCoordinatorT", bound="BraviaTVCoordinator") _P = ParamSpec("_P") @@ -61,15 +70,16 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]): self, hass: HomeAssistant, client: BraviaTV, - pin: str, - use_psk: bool, + config: MappingProxyType[str, Any], ignored_sources: list[str], ) -> None: """Initialize Bravia TV Client.""" self.client = client - self.pin = pin - self.use_psk = use_psk + self.pin = config[CONF_PIN] + self.use_psk = config.get(CONF_USE_PSK, False) + self.client_id = config.get(CONF_CLIENT_ID, LEGACY_CLIENT_ID) + self.nickname = config.get(CONF_NICKNAME, NICKNAME_PREFIX) self.ignored_sources = ignored_sources self.source: str | None = None self.source_list: list[str] = [] @@ -119,7 +129,7 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]): await self.client.connect(psk=self.pin) else: await self.client.connect( - pin=self.pin, clientid=CLIENTID_PREFIX, nickname=NICKNAME + pin=self.pin, clientid=self.client_id, nickname=self.nickname ) self.connected = True diff --git a/tests/components/braviatv/test_config_flow.py b/tests/components/braviatv/test_config_flow.py index cc70d685b78..58e684a1378 100644 --- a/tests/components/braviatv/test_config_flow.py +++ b/tests/components/braviatv/test_config_flow.py @@ -12,12 +12,16 @@ import pytest from homeassistant import data_entry_flow from homeassistant.components import ssdp from homeassistant.components.braviatv.const import ( + CONF_CLIENT_ID, CONF_IGNORED_SOURCES, + CONF_NICKNAME, CONF_USE_PSK, DOMAIN, + NICKNAME_PREFIX, ) from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_SSDP, SOURCE_USER from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PIN +from homeassistant.helpers import instance_id from tests.common import MockConfigEntry @@ -93,6 +97,7 @@ async def test_show_form(hass): async def test_ssdp_discovery(hass): """Test that the device is discovered.""" + uuid = await instance_id.async_get(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, @@ -129,6 +134,8 @@ async def test_ssdp_discovery(hass): CONF_PIN: "1234", CONF_USE_PSK: False, CONF_MAC: "AA:BB:CC:DD:EE:FF", + CONF_CLIENT_ID: uuid, + CONF_NICKNAME: f"{NICKNAME_PREFIX} {uuid[:6]}", } @@ -270,6 +277,8 @@ async def test_duplicate_error(hass): async def test_create_entry(hass): """Test that the user step works.""" + uuid = await instance_id.async_get(hass) + with patch("pybravia.BraviaTV.connect"), patch("pybravia.BraviaTV.pair"), patch( "pybravia.BraviaTV.set_wol_mode" ), patch( @@ -297,11 +306,15 @@ async def test_create_entry(hass): CONF_PIN: "1234", CONF_USE_PSK: False, CONF_MAC: "AA:BB:CC:DD:EE:FF", + CONF_CLIENT_ID: uuid, + CONF_NICKNAME: f"{NICKNAME_PREFIX} {uuid[:6]}", } async def test_create_entry_with_ipv6_address(hass): """Test that the user step works with device IPv6 address.""" + uuid = await instance_id.async_get(hass) + with patch("pybravia.BraviaTV.connect"), patch("pybravia.BraviaTV.pair"), patch( "pybravia.BraviaTV.set_wol_mode" ), patch( @@ -331,6 +344,8 @@ async def test_create_entry_with_ipv6_address(hass): CONF_PIN: "1234", CONF_USE_PSK: False, CONF_MAC: "AA:BB:CC:DD:EE:FF", + CONF_CLIENT_ID: uuid, + CONF_NICKNAME: f"{NICKNAME_PREFIX} {uuid[:6]}", }