Skip to content

Commit

Permalink
Manage status on APIv2
Browse files Browse the repository at this point in the history
Work in progress, some attributes are still not managed...
  • Loading branch information
ollo69 committed Apr 8, 2020
1 parent 0a6df35 commit 4e9676c
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 70 deletions.
25 changes: 12 additions & 13 deletions custom_components/smartthinq_washer/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
'OFF': STATE_OFF,
}

MAX_RETRIES = 4
MAX_RETRIES = 3
MAX_CONN_RETRIES = 2
MAX_LOOP_WARN = 2

Expand All @@ -86,14 +86,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
if device.type == DeviceType.WASHER:

base_name = device_name
model_info = client.model_info(device)
model = model_name + '-' + model_info.model_type

w = LGEWASHERDEVICE(client, device, base_name, model)
w = LGEWASHERDEVICE(client, device, base_name)
lge_sensors.append(w)
hass.data[DOMAIN][LGE_DEVICES][w.unique_id] = w

LOGGER.info("LGE Washer added. Name: %s - Model: %s - Mac: %s - ID: %s", base_name, model, device_mac, device_id)
LOGGER.info("LGE Washer added. Name: %s - Model: %s - Mac: %s - ID: %s", base_name, model_name, device_mac, device_id)

if lge_sensors:
async_add_entities(lge_sensors)
Expand All @@ -102,7 +100,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):


class LGEWASHERDEVICE(LGEDevice):
def __init__(self, client, device, name, model):
def __init__(self, client, device, name):

"""initialize a LGE Washer Device."""
LGEDevice.__init__(self, client, device)
Expand All @@ -119,7 +117,7 @@ def __init__(self, client, device, name, model):
self._mac = device.macaddress
self._firmware = device.firmware

self._model = model
self._model = device.model_name + '-' + self._washer.model.model_type
self._id = "%s:%s" % ("washer", device.id)

self._state = None
Expand Down Expand Up @@ -422,8 +420,8 @@ def _restart_monitor(self):
self._notlogged = True

except Exception as ex:
LOGGER.warn('Generic Wideq Error - [%s]. Exiting', str(ex))
self._notlogged = True
raise ex

def update(self):

Expand Down Expand Up @@ -462,9 +460,9 @@ def update(self):
return
#time.sleep(1)

except:
LOGGER.warn('Generic Wideq Error.')
except Exception as ex:
self._notlogged = True
raise ex

else:
if state:
Expand All @@ -474,9 +472,10 @@ def update(self):

self._retrycount = 0
self._state = state
return

LOGGER.debug('No status available yet.')
else:
LOGGER.debug('No status available yet.')

return

#time.sleep(2 ** iteration)
time.sleep(1)
Expand Down
15 changes: 9 additions & 6 deletions custom_components/smartthinq_washer/wideq/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import json
import hashlib
import hmac
import datetime
import enum
import time
import logging
from datetime import timedelta, datetime
from typing import Any, Dict, Generator, List, Optional

from . import as_list, gen_uuid
Expand Down Expand Up @@ -95,7 +95,7 @@ def lgedm_post(url, data=None, access_token=None, session_id=None, use_tlsv1=Tru
#res = requests.post(url, json={DATA_ROOT: data}, headers=headers, timeout = DEFAULT_TIMEOUT)

out = res.json()
_LOGGER.debug("lgedm2_post after: %s", out)
_LOGGER.debug("lgedm_post after: %s", out)

msg=out.get(DATA_ROOT)
if not msg:
Expand Down Expand Up @@ -195,7 +195,7 @@ def refresh_auth(oauth_root, refresh_token, use_tlsv1=True):
# through a request to the date/time endpoint:
# https://us.lgeapi.com/datetime
# But we can also just generate a timestamp.
timestamp = datetime.datetime.utcnow().strftime(DATE_FORMAT)
timestamp = datetime.utcnow().strftime(DATE_FORMAT)

# The signature for the requests is on a string consisting of two
# parts: (1) a fake request URL containing the refresh token, and (2)
Expand Down Expand Up @@ -475,7 +475,10 @@ def devices(self) -> Generator['DeviceInfo', None, None]:
if self._devices is None:
self._devices = self.session.get_devices()
return (DeviceInfo(d) for d in self._devices)


def refresh_devices(self):
return

def get_device(self, device_id) -> Optional['DeviceInfo']:
"""Look up a DeviceInfo object by device ID.
Expand Down Expand Up @@ -581,11 +584,11 @@ def oauthinfo_from_url(cls, url):

return {"access_token": access_token, "refresh_token": refresh_token}

def model_info(self, device) -> 'ModelInfo':
def model_info(self, device):
"""For a DeviceInfo object, get a ModelInfo object describing
the model's capabilities.
"""
url = device.model_info_url
if url not in self._model_info:
self._model_info[url] = device.load_model_info()
return ModelInfo(self._model_info[url])
return self._model_info[url]
44 changes: 34 additions & 10 deletions custom_components/smartthinq_washer/wideq/core_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
from urllib.parse import urljoin, urlencode, urlparse, parse_qs, quote
import hashlib
import hmac
import datetime
import logging
from datetime import timedelta, datetime
from typing import Any, Dict, Generator, List, Optional

from . import as_list, gen_uuid
from . import core_exceptions as exc
from . import core
from .device import DeviceInfo, ModelInfo, DEFAULT_TIMEOUT

import os
import json

#v2
V2_API_KEY = 'VGhpblEyLjAgU0VSVklDRQ=='
Expand Down Expand Up @@ -45,6 +47,7 @@
"0106": exc.NotConnectedError,
}

MIN_TIME_BETWEEN_UPDATE = 25 #seconds
_LOGGER = logging.getLogger(__name__)


Expand Down Expand Up @@ -193,7 +196,7 @@ def auth_request(oauth_url, data):
"""
auth_path = '/oauth/1.0/oauth2/token'
url = urljoin(oauth_url, '/oauth/1.0/oauth2/token')
timestamp = datetime.datetime.utcnow().strftime(DATE_FORMAT)
timestamp = datetime.utcnow().strftime(DATE_FORMAT)
req_url = '{}?{}'.format(auth_path, urlencode(data))
sig = oauth2_signature('{}\n{}'.format(req_url, timestamp), OAUTH_SECRET_KEY)

Expand Down Expand Up @@ -475,6 +478,7 @@ def __init__(self,
self._gateway: Optional[Gateway] = gateway
self._auth: Optional[Auth] = auth
self._session: Optional[Session] = session
self._last_device_update = datetime.now()

# The last list of devices we got from the server. This is the
# raw JSON list data describing the devices.
Expand All @@ -488,10 +492,10 @@ def __init__(self,
self._country = country
self._language = language

def _load_devices(self):
if self._session and self._devices is None:
def _load_devices(self, force_update: bool = False):
if self._session and (self._devices is None or force_update):
self._devices = self._session.get_devices()

@property
def gateway(self) -> Gateway:
if not self._gateway:
Expand Down Expand Up @@ -524,12 +528,31 @@ def devices(self) -> Generator['DeviceInfo', None, None]:
if self._devices is None:
self._load_devices()
return (DeviceInfo(d) for d in self._devices)


def _inject_thinq2_state(self):
"""This is used only for debug"""
data_file = os.path.dirname(os.path.realpath(__file__)) + '/snapshot.txt'
with open(data_file, 'r') as f:
snapshot = json.load(f)
for d in self._devices:
d.update(snapshot)

def refresh_devices(self):
call_time = datetime.now()
difference = (call_time - self._last_device_update).total_seconds()
if difference > MIN_TIME_BETWEEN_UPDATE:
self._load_devices(True)
self._last_device_update = call_time
# for debug
#self._inject_thinq2_state()
#_LOGGER.debug(self._devices)
# for debug

def get_device(self, device_id) -> Optional['DeviceInfo']:
"""Look up a DeviceInfo object by device ID.
Return None if the device does not exist.
"""
Return None if the device does not exist.
"""
for device in self.devices:
if device.id == device_id:
return device
Expand Down Expand Up @@ -603,6 +626,7 @@ def dump(self) -> Dict[str, Any]:
def refresh(self) -> None:
self._auth = self.auth.refresh()
self._session = self.auth.start_session()
#self._device = None
self._load_devices()

@classmethod
Expand Down Expand Up @@ -631,11 +655,11 @@ def oauthinfo_from_url(cls, url):

return {"oauth_url": oauth_url, "user_number": user_number, "access_token": access_token, "refresh_token": refresh_token}

def model_info(self, device) -> 'ModelInfo':
def model_info(self, device):
"""For a DeviceInfo object, get a ModelInfo object describing
the model's capabilities.
"""
url = device.model_info_url
if url not in self._model_info:
self._model_info[url] = device.load_model_info()
return ModelInfo(self._model_info[url])
return self._model_info[url]
Loading

0 comments on commit 4e9676c

Please sign in to comment.