Skip to content

Commit

Permalink
Reuse LG client_id to avoid permission error on restart
Browse files Browse the repository at this point in the history
  • Loading branch information
ollo69 committed Apr 27, 2024
1 parent 7cc1cf1 commit 0e8bc1e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 9 deletions.
29 changes: 25 additions & 4 deletions custom_components/smartthinq_sensors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ConfigEntry,
)
from homeassistant.const import (
CONF_CLIENT_ID,
CONF_REGION,
CONF_TOKEN,
MAJOR_VERSION,
Expand Down Expand Up @@ -145,7 +146,7 @@ async def get_oauth_info_from_login(
return None

async def create_client_from_token(
self, token: str, oauth_url: str | None = None
self, token: str, oauth_url: str | None = None, client_id: str | None = None
) -> ClientAsync:
"""Create a new client using refresh token."""
return await ClientAsync.from_token(
Expand All @@ -154,6 +155,7 @@ async def create_client_from_token(
language=self._language,
oauth_url=oauth_url,
aiohttp_session=self._client_session,
client_id=client_id,
)


Expand All @@ -179,7 +181,7 @@ def _notify_message(


@callback
def _migrate_old_entry_config(hass: HomeAssistant, entry: ConfigEntry) -> None:
def _migrate_old_config_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Migrate an old config entry if available."""
old_key = "outh_url" # old conf key with typo error
if old_key not in entry.data:
Expand All @@ -192,6 +194,19 @@ def _migrate_old_entry_config(hass: HomeAssistant, entry: ConfigEntry) -> None:
)


@callback
def _add_clientid_config_entry(
hass: HomeAssistant, entry: ConfigEntry, client_id: str
) -> None:
"""Add the client id to the config entry, so it can be reused."""
if CONF_CLIENT_ID in entry.data or not client_id:
return

hass.config_entries.async_update_entry(
entry, data={**entry.data, CONF_CLIENT_ID: client_id}
)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up SmartThinQ integration from a config entry."""

Expand All @@ -205,11 +220,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_LOGGER.warning(msg)
return False

_migrate_old_entry_config(hass, entry)
_migrate_old_config_entry(hass, entry)
region = entry.data[CONF_REGION]
language = entry.data[CONF_LANGUAGE]
refresh_token = entry.data[CONF_TOKEN]
oauth2_url = None # entry.data.get(CONF_OAUTH2_URL)
client_id: str | None = entry.data.get(CONF_CLIENT_ID)
use_api_v2 = entry.data.get(CONF_USE_API_V2, False)
use_ha_session = entry.data.get(CONF_USE_HA_SESSION, False)

Expand Down Expand Up @@ -249,7 +265,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# raising ConfigEntryNotReady platform setup will be retried
lge_auth = LGEAuthentication(hass, region, language, use_ha_session)
try:
client = await lge_auth.create_client_from_token(refresh_token, oauth2_url)
client = await lge_auth.create_client_from_token(
refresh_token, oauth2_url, client_id
)
except (AuthenticationError, InvalidCredentialError) as exc:
if (auth_retry := hass.data[DOMAIN].get(AUTH_RETRY, 0)) >= MAX_AUTH_RETRY:
hass.data.pop(DOMAIN)
Expand Down Expand Up @@ -290,6 +308,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

_LOGGER.debug("ThinQ client connected")

if not client_id:
_add_clientid_config_entry(hass, entry, client.client_id)

try:
lge_devices, unsupported_devices, discovered_devices = await lge_devices_setup(
hass, client
Expand Down
6 changes: 6 additions & 0 deletions custom_components/smartthinq_sensors/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Config flow for LG SmartThinQ."""

from __future__ import annotations

from collections.abc import Mapping
Expand All @@ -12,6 +13,7 @@
from homeassistant import config_entries
from homeassistant.const import (
CONF_BASE,
CONF_CLIENT_ID,
CONF_PASSWORD,
CONF_REGION,
CONF_TOKEN,
Expand Down Expand Up @@ -75,6 +77,7 @@ def __init__(self) -> None:
self._region: str | None = None
self._language: str | None = None
self._token: str | None = None
self._client_id: str | None = None
self._oauth2_url: str | None = None
self._use_ha_session = False

Expand Down Expand Up @@ -242,6 +245,7 @@ async def _check_connection(self, lge_auth: LGEAuthentication) -> int:
if not client.has_devices:
return RESULT_NO_DEV

self._client_id = client.client_id
return RESULT_SUCCESS

async def _manage_error(self, error_code: int, is_user_step=False) -> FlowResult:
Expand Down Expand Up @@ -269,6 +273,8 @@ def _save_config_entry(self) -> FlowResult:
CONF_TOKEN: self._token,
CONF_USE_API_V2: True,
}
if self._client_id:
data[CONF_CLIENT_ID] = self._client_id
if self._oauth2_url:
data[CONF_OAUTH2_URL] = self._oauth2_url
if self._use_ha_session:
Expand Down
34 changes: 29 additions & 5 deletions custom_components/smartthinq_sensors/wideq/core_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ def __init__(
timeout: int = DEFAULT_TIMEOUT,
oauth_url: str | None = None,
session: aiohttp.ClientSession | None = None,
client_id: str | None = None,
):
"""
Create the CoreAsync object
Expand All @@ -180,7 +181,7 @@ def __init__(
self._language = language
self._timeout = aiohttp.ClientTimeout(total=timeout)
self._oauth_url = oauth_url
self._client_id = None
self._client_id = client_id
self._lang_pack_url = None

if session:
Expand All @@ -191,12 +192,12 @@ def __init__(
self._managed_session = True

@property
def country(self):
def country(self) -> str:
"""Return the used country."""
return self._country

@property
def language(self):
def language(self) -> str:
"""Return the used language."""
return self._language

Expand All @@ -205,6 +206,11 @@ def lang_pack_url(self):
"""Return the used language."""
return self._lang_pack_url

@property
def client_id(self) -> str | None:
"""Return the associated client_id."""
return self._client_id

async def close(self):
"""Close the managed session on exit."""
if self._managed_session and self._session:
Expand All @@ -220,6 +226,7 @@ def _get_session(self) -> aiohttp.ClientSession:
def _get_client_id(self, user_number: str | None = None) -> str:
"""Generate a new clent ID or return existing."""
if self._client_id is not None:
_LOGGER.info("Client ID: %s", self._client_id)
return self._client_id
if user_number is None:
return None
Expand Down Expand Up @@ -1425,6 +1432,13 @@ def auth(self) -> Auth:
assert False, "unauthenticated"
return self._auth

@property
def client_id(self) -> str | None:
"""Return the associated client_id."""
if not self._auth:
return None
return self._auth.gateway.core.client_id

@property
def session(self) -> Session:
"""Return the Session object associated to this client."""
Expand Down Expand Up @@ -1506,6 +1520,7 @@ async def from_user_login(
language: str = DEFAULT_LANGUAGE,
oauth_url: str | None = None,
aiohttp_session: aiohttp.ClientSession | None = None,
client_id: str | None = None,
enable_emulation: bool = False,
) -> ClientAsync:
"""
Expand All @@ -1517,7 +1532,11 @@ async def from_user_login(
"""

core = CoreAsync(
country, language, oauth_url=oauth_url, session=aiohttp_session
country,
language,
oauth_url=oauth_url,
session=aiohttp_session,
client_id=client_id,
)
try:
gateway = await Gateway.discover(core)
Expand Down Expand Up @@ -1545,6 +1564,7 @@ async def from_token(
language: str = DEFAULT_LANGUAGE,
oauth_url: str | None = None,
aiohttp_session: aiohttp.ClientSession | None = None,
client_id: str | None = None,
enable_emulation: bool = False,
) -> ClientAsync:
"""
Expand All @@ -1556,7 +1576,11 @@ async def from_token(
"""

core = CoreAsync(
country, language, oauth_url=oauth_url, session=aiohttp_session
country,
language,
oauth_url=oauth_url,
session=aiohttp_session,
client_id=client_id,
)
try:
gateway = await Gateway.discover(core)
Expand Down

0 comments on commit 0e8bc1e

Please sign in to comment.