forked from marciogranzotto/hass-smartthinq
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path__init__.py
229 lines (183 loc) · 7.01 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
"""
Support for LG Smartthinq devices.
"""
import asyncio
import json
import logging
import os
from typing import Dict
from urllib.parse import parse_qs, urlencode, urljoin, urlparse
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
import wideq
from homeassistant import config_entries
from homeassistant.const import CONF_REGION, CONF_TOKEN
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import discovery
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import HomeAssistantType
from wideq import Client
from wideq.core import (Auth, InvalidCredentialError, NotConnectedError,
NotLoggedInError, TokenError)
from .const import (CLIENT, CONF_LANGUAGE, CONF_OAUTH_URL, CONF_OAUTH_USER_NUM,
CONF_WIDEQ_STATE, DOMAIN, LGE_DEVICES,
SMARTTHINQ_COMPONENTS, STARTUP)
_LOGGER = logging.getLogger(__name__)
KEY_SMARTTHINQ_DEVICES = "smartthinq_devices"
README_URL = "https://github.com/marciogranzotto/hass-smartthinq/blob/master/README.md"
class LGDevice(Entity):
def __init__(self, client, device):
self._client = client
self._device = device
@property
def name(self):
return self._device.name
@property
def available(self):
return True
class LGEAuthentication:
def __init__(self, region, language):
self._region = region
self._language = language
def _create_client(self):
client = Client(country=self._region, language=self._language)
return client
def getLoginUrl(self) -> str:
login_url = None
client = self._create_client()
try:
login_url = client.gateway.oauth_url()
except Exception:
_LOGGER.exception("Error retrieving login URL from ThinQ")
return login_url
def getOAuthInfoFromUrl(self, callback_url) -> Dict[str, str]:
oauth_info = None
try:
client = self._create_client()
auth = Auth.from_url(client.gateway, callback_url)
out = {
"oauth_url": auth.oauth_root,
"user_number": auth.user_number,
"access_token": auth.access_token,
"refresh_token": auth.refresh_token,
}
_LOGGER.info(out)
return out
except Exception:
_LOGGER.exception("Error retrieving OAuth info from ThinQ")
return oauth_info
def getOAuthFromUrl(self, callback_url) -> Auth:
try:
client = self._create_client()
return Auth.from_url(client.gateway, callback_url)
except Exception:
_LOGGER.exception("Error retrieving OAuth info from ThinQ")
return None
def createClientWithAuth(self, auth):
client = self._create_client()
client._auth = auth
client.refresh()
client._devices = client.session.get_devices()
return client
def createClientFromToken(self, token, oauth_url=None, oauth_user_num=None):
client = self._create_client()
client._auth = Auth(client.gateway, None, token, oauth_user_num, oauth_url)
client.refresh()
client._devices = client.session.get_devices()
return client
async def async_setup(hass, config):
"""
This method gets called if HomeAssistant has a valid configuration entry within
configurations.yaml.
Thus, in this method we simply trigger the creation of a config entry.
:return:
"""
conf = config.get(DOMAIN)
hass.data[DOMAIN] = {}
if conf is not None:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=conf
)
)
return True
async def async_setup_entry(hass: HomeAssistantType, config_entry):
"""
This class is called by the HomeAssistant framework when a configuration entry is provided.
"""
refresh_token = config_entry.data.get(CONF_TOKEN)
region = config_entry.data.get(CONF_REGION)
language = config_entry.data.get(CONF_LANGUAGE)
oauth_url = config_entry.data.get(CONF_OAUTH_URL)
oauth_user_num = config_entry.data.get(CONF_OAUTH_USER_NUM)
_LOGGER.info(STARTUP)
_LOGGER.info(
"Initializing ThinQ platform with region: %s - language: %s",
region,
language,
)
hass.data.setdefault(DOMAIN, {})[LGE_DEVICES] = {}
# if network is not connected we can have some error
# raising ConfigEntryNotReady platform setup will be retried
lgeauth = LGEAuthentication(region, language)
try:
client = await hass.async_add_executor_job(
lgeauth.createClientFromToken, refresh_token, oauth_url, oauth_user_num
)
except InvalidCredentialError:
_LOGGER.error("Invalid ThinQ credential error. Component setup aborted")
return False
except Exception:
_LOGGER.warning(
"Connection not available. ThinQ platform not ready", exc_info=True
)
raise ConfigEntryNotReady()
if not client._devices:
_LOGGER.error("No ThinQ devices found. Component setup aborted")
return False
_LOGGER.info("ThinQ client connected")
try:
hass.data[CONF_WIDEQ_STATE] = client.dump()
await lge_devices_setup(hass, client, config_entry)
except Exception:
_LOGGER.warning(
"Connection not available. ThinQ platform not ready", exc_info=True
)
raise ConfigEntryNotReady()
for platform in SMARTTHINQ_COMPONENTS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, platform)
)
return True
async def async_unload_entry(hass, config_entry):
"""Unload a config entry."""
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(config_entry, platform)
for platform in SMARTTHINQ_COMPONENTS
]
)
hass.data.pop(DOMAIN)
return True
async def lge_devices_setup(hass, client, config_entry):
"""Query connected devices from LG ThinQ."""
_LOGGER.info("Starting LGE ThinQ devices...")
device_count = 0
if KEY_SMARTTHINQ_DEVICES not in hass.data:
hass.data[KEY_SMARTTHINQ_DEVICES] = []
while True:
try:
for device in client.devices:
hass.data[KEY_SMARTTHINQ_DEVICES].append(device.id)
_LOGGER.info("Found LGE Device with Name: {} - Type: {} - InfoUrl: {}".format(
device.name,
device.type.name,
device.model_info_url))
for component in SMARTTHINQ_COMPONENTS:
discovery.load_platform(hass, component, DOMAIN, {}, config_entry)
device_count += 1
_LOGGER.info("Founds %s LGE device(s)", str(device_count))
return
except wideq.NotLoggedInError:
_LOGGER.info("Session expired.")
client.refresh()